From 2dcbc539492043a3480f01352620080e766de773 Mon Sep 17 00:00:00 2001 From: Valeriy Van Date: Fri, 17 Apr 2020 22:51:28 +0200 Subject: [PATCH 001/663] Removes redundant buffer zeroing in foreignErrorCorrectedGrapheme func --- stdlib/public/core/UnicodeHelpers.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stdlib/public/core/UnicodeHelpers.swift b/stdlib/public/core/UnicodeHelpers.swift index 64e7ea189fd9f..1e538f9349d4b 100644 --- a/stdlib/public/core/UnicodeHelpers.swift +++ b/stdlib/public/core/UnicodeHelpers.swift @@ -397,12 +397,13 @@ extension _StringGuts { } // TODO(String performance): Stack buffer if small enough - var cus = Array(repeating: 0, count: count) - cus.withUnsafeMutableBufferPointer { + let cus = Array(unsafeUninitializedCapacity: count) { + buffer, initializedCapacity in _cocoaStringCopyCharacters( from: self._object.cocoaObject, range: start.. Date: Tue, 9 Jun 2020 06:05:05 -0400 Subject: [PATCH 002/663] Keep master-next building and tested --- lib/Frontend/ModuleInterfaceLoader.cpp | 2 +- lib/FrontendTool/FrontendTool.cpp | 4 ++-- lib/Serialization/ModuleFile.cpp | 2 +- lib/Serialization/Serialization.cpp | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 8cc5fb2a9e67e..2304ee08b16ef 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1165,7 +1165,7 @@ bool InterfaceSubContextDelegateImpl::extractSwiftInterfaceVersionAndArgs( } void InterfaceSubContextDelegateImpl::addExtraClangArg(StringRef arg) { - subInvocation.getClangImporterOptions().ExtraArgs.push_back(arg); + subInvocation.getClangImporterOptions().ExtraArgs.push_back(arg.str()); GenericArgs.push_back("-Xcc"); GenericArgs.push_back(ArgSaver.save(arg)); } diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7edaacc2ea557..ad63b1e98b6bf 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -179,14 +179,14 @@ static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags, reversePathSortedFilenames(opts.InputsAndOutputs.getInputFilenames()); for (auto const &path : inputPaths) { dependencyString.push_back(' '); - dependencyString.append(frontend::utils::escapeForMake(path, buffer)); + dependencyString.append(frontend::utils::escapeForMake(path, buffer).str()); } // Then print dependencies we've picked up during compilation. auto dependencyPaths = reversePathSortedFilenames(depTracker->getDependencies()); for (auto const &path : dependencyPaths) { dependencyString.push_back(' '); - dependencyString.append(frontend::utils::escapeForMake(path, buffer)); + dependencyString.append(frontend::utils::escapeForMake(path, buffer).str()); } // FIXME: Xcode can't currently handle multiple targets in a single diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index e9e789fcf69da..3f9354e09338e 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -2210,7 +2210,7 @@ ModuleFile::getModuleName(ASTContext &Ctx, StringRef modulePath, nullptr, /*isFramework*/isFramework, loadedModuleFile, &ExtInfo); - Name = loadedModuleFile->Name; + Name = loadedModuleFile->Name.str(); return std::move(loadedModuleFile->ModuleInputBuffer); } diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 21c3bf40f5fa6..ec145556d931c 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -46,6 +46,7 @@ #include "swift/Demangling/ManglingMacros.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Strings.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/RecordLayout.h" From 6f03b3ec75af0efb237845692785787121433fb7 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Wed, 10 Jun 2020 08:22:27 -0700 Subject: [PATCH 003/663] Fix compile error in ScanDependencies --- lib/FrontendTool/ScanDependencies.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 3487946ca3346..9c402f4765459 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -164,7 +164,9 @@ static std::vector resolveDirectDependencies( /*onlyClangModule=*/false, cache, ASTDelegate)) { - result.push_back({overlayName.str(), found->getKind()}); + auto overlayId = + ModuleDependencyID{overlayName.str(), found->getKind()}; + result.push_back(overlayId); } } }); From 003b86d67569642235b9543ae1da35fcabd6654b Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Wed, 10 Jun 2020 08:27:08 -0700 Subject: [PATCH 004/663] Fix debug info test vector.swift rdar://64192814 --- test/DebugInfo/vector.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/DebugInfo/vector.swift b/test/DebugInfo/vector.swift index d815055df63ff..f50164ce1f54f 100644 --- a/test/DebugInfo/vector.swift +++ b/test/DebugInfo/vector.swift @@ -4,7 +4,7 @@ // CHECK: !DICompositeType(tag: DW_TAG_array_type, baseType: ![[FLOAT:[0-9]+]], size: 64, flags: DIFlagVector, elements: ![[ELTS:[0-9]+]]) // CHECK: ![[FLOAT]] = !DIBasicType(name: "$sBf32_D", size: 32, encoding: DW_ATE_float) // CHECK: ![[ELTS]] = !{![[SR:[0-9]+]]} -// CHECK: ![[SR]] = !DISubrange(count: 2) +// CHECK: ![[SR]] = !DISubrange(count: 2, lowerBound: 0) import Swift From b675ddb411ef81d6a91a9402909cc148dd46b861 Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Thu, 11 Jun 2020 06:10:42 -0400 Subject: [PATCH 005/663] Add missing header --- lib/Driver/FrontendUtil.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Driver/FrontendUtil.cpp b/lib/Driver/FrontendUtil.cpp index 7d796ddfc722c..75b95de1b6d0f 100644 --- a/lib/Driver/FrontendUtil.cpp +++ b/lib/Driver/FrontendUtil.cpp @@ -20,6 +20,7 @@ #include "swift/Driver/ToolChain.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h" #include "llvm/Support/StringSaver.h" using namespace swift; From 83966b2feb02ae72caef83e91273698d758f58b4 Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Fri, 12 Jun 2020 08:47:50 -0400 Subject: [PATCH 006/663] Track upstream clang API rename In 2e92b397ae4bd846d34d151749ef09c1a1b81dab, `isHidden` was renamed and the result polarity was inversed. --- lib/ClangImporter/ClangImporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index cad4a0b098dec..941bf629b29a0 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2889,11 +2889,11 @@ void ClangModuleUnit::lookupValue(DeclName name, NLKind lookupKind, bool ClangImporter::Implementation::isVisibleClangEntry( const clang::NamedDecl *clangDecl) { // For a declaration, check whether the declaration is hidden. - if (!clangDecl->isHidden()) return true; + if (clangDecl->isUnconditionallyVisible()) return true; // Is any redeclaration visible? for (auto redecl : clangDecl->redecls()) { - if (!cast(redecl)->isHidden()) return true; + if (cast(redecl)->isUnconditionallyVisible()) return true; } return false; From d659ab0b78e480dff4bc397daf82cd1225d94434 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 12 Jun 2020 10:07:59 -0700 Subject: [PATCH 007/663] Adapt to upstream changes in https://reviews.llvm.org/D81732 --- lib/ClangImporter/ClangImporter.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 941bf629b29a0..e848b2dc8e2a5 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2889,12 +2889,14 @@ void ClangModuleUnit::lookupValue(DeclName name, NLKind lookupKind, bool ClangImporter::Implementation::isVisibleClangEntry( const clang::NamedDecl *clangDecl) { // For a declaration, check whether the declaration is hidden. - if (clangDecl->isUnconditionallyVisible()) return true; + auto &clangSema = Instance->getSema(); + if (clangSema.isVisible(clangDecl)) + return true; // Is any redeclaration visible? - for (auto redecl : clangDecl->redecls()) { - if (cast(redecl)->isUnconditionallyVisible()) return true; - } + for (auto redecl : clangDecl->redecls()) + if (clangSema.isVisible(cast(redecl))) + return true; return false; } From 79df34214633ce02770989dd066a816c22183f7f Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Mon, 15 Jun 2020 06:00:20 -0400 Subject: [PATCH 008/663] Do not hardcode SVE type list --- lib/ClangImporter/ClangAdapter.cpp | 15 +++------------ lib/ClangImporter/ImportType.cpp | 15 +++------------ lib/IRGen/GenCall.cpp | 15 +++------------ 3 files changed, 9 insertions(+), 36 deletions(-) diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp index 8d6c05e55f2d1..32fc1cf534bf0 100644 --- a/lib/ClangImporter/ClangAdapter.cpp +++ b/lib/ClangImporter/ClangAdapter.cpp @@ -453,18 +453,9 @@ OmissionTypeName importer::getClangTypeNameForOmission(clang::ASTContext &ctx, return OmissionTypeName(); // SVE builtin types that don't have Swift equivalents. - case clang::BuiltinType::SveInt8: - case clang::BuiltinType::SveInt16: - case clang::BuiltinType::SveInt32: - case clang::BuiltinType::SveInt64: - case clang::BuiltinType::SveUint8: - case clang::BuiltinType::SveUint16: - case clang::BuiltinType::SveUint32: - case clang::BuiltinType::SveUint64: - case clang::BuiltinType::SveFloat16: - case clang::BuiltinType::SveFloat32: - case clang::BuiltinType::SveFloat64: - case clang::BuiltinType::SveBool: +#define SVE_TYPE(Name, Id, ...) \ + case clang::BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" return OmissionTypeName(); } } diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 39c76bef1df49..b4aeae69d82c2 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -350,18 +350,9 @@ namespace { return Type(); // SVE builtin types that don't have Swift equivalents. - case clang::BuiltinType::SveInt8: - case clang::BuiltinType::SveInt16: - case clang::BuiltinType::SveInt32: - case clang::BuiltinType::SveInt64: - case clang::BuiltinType::SveUint8: - case clang::BuiltinType::SveUint16: - case clang::BuiltinType::SveUint32: - case clang::BuiltinType::SveUint64: - case clang::BuiltinType::SveFloat16: - case clang::BuiltinType::SveFloat32: - case clang::BuiltinType::SveFloat64: - case clang::BuiltinType::SveBool: +#define SVE_TYPE(Name, Id, ...) \ + case clang::BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" return Type(); } diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 18e2f8a66135e..bd530aac23ac9 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -882,18 +882,9 @@ namespace { llvm_unreachable("OpenCL type in ABI lowering"); // We should never see the SVE types at all. - case clang::BuiltinType::SveInt8: - case clang::BuiltinType::SveInt16: - case clang::BuiltinType::SveInt32: - case clang::BuiltinType::SveInt64: - case clang::BuiltinType::SveUint8: - case clang::BuiltinType::SveUint16: - case clang::BuiltinType::SveUint32: - case clang::BuiltinType::SveUint64: - case clang::BuiltinType::SveFloat16: - case clang::BuiltinType::SveFloat32: - case clang::BuiltinType::SveFloat64: - case clang::BuiltinType::SveBool: +#define SVE_TYPE(Name, Id, ...) \ + case clang::BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" llvm_unreachable("SVE type in ABI lowering"); // Handle all the integer types as opaque values. From a5ef6f28b24553bad449277b9649e7811186a59a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 15 Jun 2020 11:19:18 -0700 Subject: [PATCH 009/663] Adapt to ScanDeps to StringRef conversion removal rdar://64263902 --- lib/FrontendTool/ScanDependencies.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index ab0c1f4160c59..fec2f01fe1b16 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -164,7 +164,7 @@ static std::vector resolveDirectDependencies( /*onlyClangModule=*/false, cache, ASTDelegate)) { - result.emplace_back(overlayName.str(), found->getKind()); + result.emplace_back(overlayName.str().str(), found->getKind()); } } }); From c0c976355c4c2aa05cc12eb531a1eac6de9320aa Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Thu, 18 Jun 2020 06:14:00 -0400 Subject: [PATCH 010/663] Adapt a swift/master change to master-next (StringRef vs std::string) --- lib/Frontend/ModuleInterfaceLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 6ded06f095837..9dc0a8570d6d7 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1223,7 +1223,7 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( // FIXME: we shouldn't need this. Remove it? StringRef explictSwiftModuleMap = searchPathOpts.ExplicitSwiftModuleMap; subInvocation.getSearchPathOptions().ExplicitSwiftModuleMap = - explictSwiftModuleMap; + explictSwiftModuleMap.str(); if (!explictSwiftModuleMap.empty()) { GenericArgs.push_back("-explicit-swift-module-map-file"); GenericArgs.push_back(explictSwiftModuleMap); From b7664fa3200c4d7be6299ffb814e3210078b05e6 Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Wed, 24 Jun 2020 14:41:28 -0400 Subject: [PATCH 011/663] [IRGen] Adjust to upstream LLVM change GlobalValue::getAlignment() was removed in a2caa3b61497b6be8c8b77823d0fd62b4be1f177. --- lib/IRGen/GenDecl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 50508e1e18c83..fc76a886dd3ce 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -4306,7 +4306,7 @@ static Address getAddrOfSimpleVariable(IRGenModule &IGM, // Check whether it's already cached. llvm::Constant *&entry = cache[entity]; if (entry) { - auto existing = cast(entry); + auto existing = cast(entry); assert(alignment == Alignment(existing->getAlignment())); if (forDefinition) updateLinkageForDefinition(IGM, existing, entity); return Address(entry, alignment); From a6b0e926fd3b5ceceac30220ee9303d5fa279be3 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Sun, 29 Dec 2019 22:56:03 -0500 Subject: [PATCH 012/663] [stdlib] Both FreeBSD and OpenBSD use environ. However, when building Glibc with assertions enabled, LLVM asserts in CodeGenModule::EmitGlobal with "Cannot emit local var decl as global". This assert is _probably_ wrong in LLVM because the local extern reference isn't being handled properly and needs to be addressed there. We could move the declaration to global scope, but that is not ideal because it makes the pointer declaration visible to Swift. OpenBSD needs to implement _swift_stdlib_getEnviron regardless, so let's do so. --- stdlib/public/SwiftShims/LibcOverlayShims.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/SwiftShims/LibcOverlayShims.h b/stdlib/public/SwiftShims/LibcOverlayShims.h index b4c2ba1d0a002..6395656355330 100644 --- a/stdlib/public/SwiftShims/LibcOverlayShims.h +++ b/stdlib/public/SwiftShims/LibcOverlayShims.h @@ -52,7 +52,7 @@ static inline int _swift_stdlib_fcntlPtr(int fd, int cmd, void* ptr) { #endif // Environment -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) static inline char * _Nullable * _Null_unspecified _swift_stdlib_getEnviron() { extern char **environ; return environ; From f7318dbb01c16cbb4a8b1b3443123217ae5da2c2 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 29 Jun 2020 14:59:59 -0700 Subject: [PATCH 013/663] [Docs] Fix Sphinx duplicate term description error. Modules.rst:duplicate term description of module, other instance in Modules Modules.rst:463:duplicate term description of target, other instance in LibraryEvolution --- docs/Modules.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/Modules.rst b/docs/Modules.rst index fbea23d6c8b4b..fbaa3864313c5 100644 --- a/docs/Modules.rst +++ b/docs/Modules.rst @@ -441,10 +441,6 @@ Glossary __ https://en.wikipedia.org/wiki/Name_mangling#C.2B.2B - module - An entity containing the API for a library, to be `imported ` into - a source file. - qualified name A multi-piece name like ``Foundation.NSWindow``, which names an entity within a particular context. This document is concerned with the case where @@ -463,9 +459,3 @@ Glossary SIL "Swift Intermediate Language", a stable IR for the distribution of inlineable code. - - - target - A dynamic library, framework, plug-in, or application to be built. - A natural LTO boundary, and roughly the same as what Xcode requires - separate targets to build. From 66bddd6e4cbe04e6942debbb538a33a5ebb04e15 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 29 Jun 2020 15:29:07 -0700 Subject: [PATCH 014/663] [ClangImporter] Adjust for LLVM API change --- lib/ClangImporter/ImportDecl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 91d2987bfa182..f52144cdfc6f0 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1232,7 +1232,7 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl, clang::VK_RValue, clang::OK_Ordinary, clang::SourceLocation(), - clang::FPOptions()); + clang::FPOptionsOverride()); cSetterDecl->setBody(cSetterExpr); } From 0fe540f83672351fa733ef976022d38e0a6e492e Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Fri, 3 Jul 2020 07:18:35 -0400 Subject: [PATCH 015/663] Track upstream llvm change to enum definition See LLVM commit: 3587c9c4275b96e7a7ddc4eeb6a001b7d03b55bb --- include/swift/AST/Builtins.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/AST/Builtins.h b/include/swift/AST/Builtins.h index 1654e7cc4cc3d..516f7dce7376a 100644 --- a/include/swift/AST/Builtins.h +++ b/include/swift/AST/Builtins.h @@ -26,7 +26,7 @@ #include "llvm/Support/ErrorHandling.h" namespace llvm { -enum class AtomicOrdering; +enum class AtomicOrdering : unsigned; } namespace swift { From 4fd0cdc2efddd3eb64ad279a29af3b9779d56399 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Tue, 7 Jul 2020 14:47:16 -0700 Subject: [PATCH 016/663] Fix up calls to clang::Type::dump() now that it requires a clang::ASTContext. --- include/swift/AST/PrettyStackTrace.h | 7 +++++-- lib/AST/ASTDumper.cpp | 4 +++- lib/AST/PrettyStackTrace.cpp | 2 +- lib/AST/Type.cpp | 4 ++-- lib/Serialization/Serialization.cpp | 6 ++++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/swift/AST/PrettyStackTrace.h b/include/swift/AST/PrettyStackTrace.h index 51d047ecbb1b5..84cc4db780d18 100644 --- a/include/swift/AST/PrettyStackTrace.h +++ b/include/swift/AST/PrettyStackTrace.h @@ -26,6 +26,7 @@ namespace clang { class Type; + class ASTContext; } namespace swift { @@ -141,11 +142,13 @@ class PrettyStackTraceType : public llvm::PrettyStackTraceEntry { /// PrettyStackTraceClangType - Observe that we are processing a /// specific Clang type. class PrettyStackTraceClangType : public llvm::PrettyStackTraceEntry { + const clang::ASTContext &Context; const clang::Type *TheType; const char *Action; public: - PrettyStackTraceClangType(const char *action, const clang::Type *type) - : TheType(type), Action(action) {} + PrettyStackTraceClangType(clang::ASTContext &ctx, + const char *action, const clang::Type *type) + : Context(ctx), TheType(type), Action(action) {} virtual void print(llvm::raw_ostream &OS) const; }; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index df7b9e300fc23..c9a755315eb2f 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3752,7 +3752,9 @@ namespace { if (auto *cty = T->getClangFunctionType()) { std::string s; llvm::raw_string_ostream os(s); - cty->dump(os); + auto &ctx = T->getASTContext().getClangModuleLoader() + ->getClangASTContext(); + cty->dump(os, ctx); printField("clang_type", os.str()); } printAnyFunctionParams(T->getParams(), "input"); diff --git a/lib/AST/PrettyStackTrace.cpp b/lib/AST/PrettyStackTrace.cpp index a13caf0683dab..dc07100062991 100644 --- a/lib/AST/PrettyStackTrace.cpp +++ b/lib/AST/PrettyStackTrace.cpp @@ -217,7 +217,7 @@ void PrettyStackTraceClangType::print(llvm::raw_ostream &out) const { out << "NULL clang type!\n"; return; } - TheType->dump(out); + TheType->dump(out, Context); } void PrettyStackTraceTypeRepr::print(llvm::raw_ostream &out) const { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 4c59a9f812fa5..52ce70d4ea659 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3388,8 +3388,8 @@ AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) { SmallString<256> buf; llvm::raw_svector_ostream os(buf); os << "Expected a Clang function type wrapped in a pointer type or " - << "a block pointer type but found:\n"; - type->dump(os); + << "a block pointer type but found:\n "; + // type->dump(os); llvm_unreachable(os.str().data()); } #endif diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 53050bdb37ae1..e0a5ac830bedf 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -611,7 +611,8 @@ serialization::ClangTypeID Serializer::addClangTypeRef(const clang::Type *ty) { isSerializable = false; } if (!isSerializable) { - PrettyStackTraceClangType trace("staging a serialized reference to", ty); + PrettyStackTraceClangType trace(loader->getClangASTContext(), + "staging a serialized reference to", ty); llvm::report_fatal_error("Clang function type is not serializable"); } @@ -4396,7 +4397,8 @@ class ClangToSwiftBasicWriter : void Serializer::writeASTBlockEntity(const clang::Type *ty) { using namespace decls_block; - PrettyStackTraceClangType traceRAII("serializing clang type", ty); + auto &ctx = getASTContext().getClangModuleLoader()->getClangASTContext(); + PrettyStackTraceClangType traceRAII(ctx, "serializing clang type", ty); assert(ClangTypesToSerialize.hasRef(ty)); // Serialize the type as an opaque sequence of data. From 3957574a7b62aa7f6660a117c75eb83103224a9d Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Tue, 7 Jul 2020 17:55:28 -0700 Subject: [PATCH 017/663] Fixup code that was using the now-removed DominatorTreeBase::getRoots() Use the new roots(), roots_begin(), etc. instead. --- include/swift/SILOptimizer/Analysis/DominanceAnalysis.h | 4 ++-- lib/SIL/Utils/Dominance.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h b/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h index 2b3b5d121756b..6afbc0ad36eaf 100644 --- a/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h @@ -24,7 +24,7 @@ class SILInstruction; class DominanceAnalysis : public FunctionAnalysisBase { protected: virtual void verify(DominanceInfo *DI) const override { - if (DI->getRoots().empty()) + if (DI->roots().empty()) return; DI->verify(); } @@ -52,7 +52,7 @@ class DominanceAnalysis : public FunctionAnalysisBase { class PostDominanceAnalysis : public FunctionAnalysisBase { protected: virtual void verify(PostDominanceInfo *PDI) const override { - if (PDI->getRoots().empty()) + if (PDI->roots().empty()) return; PDI->verify(); } diff --git a/lib/SIL/Utils/Dominance.cpp b/lib/SIL/Utils/Dominance.cpp index 88e034ca64ca8..ad91ee6f3c547 100644 --- a/lib/SIL/Utils/Dominance.cpp +++ b/lib/SIL/Utils/Dominance.cpp @@ -119,7 +119,7 @@ void PostDominanceInfo::verify() const { // // Even though at the SIL level we have "one" return function, we can have // multiple exits provided by no-return functions. - auto *F = getRoots()[0]->getParent(); + auto *F = (*root_begin())->getParent(); PostDominanceInfo OtherDT(F); // And compare. From 4861f3174f547343ba0ceaf370e35677885c34a2 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Mon, 13 Jul 2020 11:29:30 -0700 Subject: [PATCH 018/663] Fix call for upstream llvm change of ClangDecl::isInLocalScope() After f721e0582b158c60c56d2601235b6d60758f4d7a in llvm it's now called isInLocalScopeForInstantiation() and returns false if the context is not dependent on a template parameter, so doesn't have the desired behavior for the single swift caller in the clang importer. This pulls out the old logic into a new static isLocalScope() function in ClangAdapter.cpp. --- lib/ClangImporter/ClangAdapter.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp index 32fc1cf534bf0..3f5acc3f7c2a0 100644 --- a/lib/ClangImporter/ClangAdapter.cpp +++ b/lib/ClangImporter/ClangAdapter.cpp @@ -77,11 +77,26 @@ importer::getDefinitionForClangTypeDecl(const clang::Decl *D) { return None; } +static bool isInLocalScope(const clang::Decl *D) { + const clang::DeclContext *LDC = D->getLexicalDeclContext(); + while (true) { + if (LDC->isFunctionOrMethod()) + return true; + if (!isa(LDC)) + return false; + if (const auto *CRD = dyn_cast(LDC)) + if (CRD->isLambda()) + return true; + LDC = LDC->getLexicalParent(); + } + return false; +} + const clang::Decl * importer::getFirstNonLocalDecl(const clang::Decl *D) { D = D->getCanonicalDecl(); auto iter = llvm::find_if(D->redecls(), [](const clang::Decl *next) -> bool { - return !next->isInLocalScope(); + return !isInLocalScope(next); }); if (iter == D->redecls_end()) return nullptr; From e284d7e8e5f4707abe39f5c2b7ea2f8b7eb1ab5b Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 13 Jul 2020 20:42:53 -0700 Subject: [PATCH 019/663] [TBDGen] Make enumeratePublicSymbols more functional Instead of taking an out parameter, have it return the set directly. Also coalesce the two overloads into a single overload that takes a `TBDGenDescriptor`. (cherry picked from commit 0e97ecedd6ac4df22051d81861e3eb74c35d9d3c) --- include/swift/TBDGen/TBDGen.h | 6 ++---- lib/FrontendTool/FrontendTool.cpp | 20 +++++++++++--------- lib/FrontendTool/TBD.cpp | 8 ++------ lib/TBDGen/TBDGen.cpp | 16 +++------------- 4 files changed, 18 insertions(+), 32 deletions(-) diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 1da2386d3132a..67863bb949021 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -14,6 +14,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringSet.h" +#include "swift/AST/TBDGenRequests.h" #include "swift/Basic/Version.h" #include @@ -88,10 +89,7 @@ struct TBDGenOptions { } }; -void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols, - const TBDGenOptions &opts); -void enumeratePublicSymbols(ModuleDecl *module, llvm::StringSet<> &symbols, - const TBDGenOptions &opts); +llvm::StringSet<> getPublicSymbols(TBDGenDescriptor desc); void writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os, const TBDGenOptions &opts); diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7afd65f4be4ab..b08c488226992 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1053,9 +1053,9 @@ static bool writeLdAddCFileIfNeeded(CompilerInstance &Instance) { } auto tbdOpts = Invocation.getTBDGenOptions(); tbdOpts.LinkerDirectivesOnly = true; - llvm::StringSet<> ldSymbols; auto *module = Instance.getMainModule(); - enumeratePublicSymbols(module, ldSymbols, tbdOpts); + auto ldSymbols = + getPublicSymbols(TBDGenDescriptor::forModule(module, tbdOpts)); std::error_code EC; llvm::raw_fd_ostream OS(Path, EC, llvm::sys::fs::F_None); if (EC) { @@ -1662,15 +1662,17 @@ static bool generateCode(CompilerInstance &Instance, StringRef OutputFilename, OutputFilename, Instance.getStatsReporter()); } -static void collectLinkerDirectives(const CompilerInvocation &Invocation, - ModuleOrSourceFile MSF, - llvm::StringSet<> &Symbols) { +static llvm::StringSet<> +collectLinkerDirectives(const CompilerInvocation &Invocation, + ModuleOrSourceFile MSF) { auto tbdOpts = Invocation.getTBDGenOptions(); tbdOpts.LinkerDirectivesOnly = true; - if (MSF.is()) - enumeratePublicSymbols(MSF.get(), Symbols, tbdOpts); - else - enumeratePublicSymbols(MSF.get(), Symbols, tbdOpts); + if (auto *SF = MSF.dyn_cast()) { + return getPublicSymbols(TBDGenDescriptor::forFile(SF, tbdOpts)); + } else { + return getPublicSymbols( + TBDGenDescriptor::forModule(MSF.get(), tbdOpts)); + } } static bool performCompileStepsPostSILGen(CompilerInstance &Instance, diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp index f466c8e5b94d5..5697ddf0a41e9 100644 --- a/lib/FrontendTool/TBD.cpp +++ b/lib/FrontendTool/TBD.cpp @@ -139,9 +139,7 @@ bool swift::validateTBD(ModuleDecl *M, const llvm::Module &IRModule, const TBDGenOptions &opts, bool diagnoseExtraSymbolsInTBD) { - llvm::StringSet<> symbols; - enumeratePublicSymbols(M, symbols, opts); - + auto symbols = getPublicSymbols(TBDGenDescriptor::forModule(M, opts)); return validateSymbolSet(M->getASTContext().Diags, symbols, IRModule, diagnoseExtraSymbolsInTBD); } @@ -150,9 +148,7 @@ bool swift::validateTBD(FileUnit *file, const llvm::Module &IRModule, const TBDGenOptions &opts, bool diagnoseExtraSymbolsInTBD) { - llvm::StringSet<> symbols; - enumeratePublicSymbols(file, symbols, opts); - + auto symbols = getPublicSymbols(TBDGenDescriptor::forFile(file, opts)); return validateSymbolSet(file->getParentModule()->getASTContext().Diags, symbols, IRModule, diagnoseExtraSymbolsInTBD); diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index a8685bcc06324..8a20be39a2413 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -1185,19 +1185,9 @@ GenerateTBDRequest::evaluate(Evaluator &evaluator, return std::make_pair(std::move(file), std::move(symbols)); } -void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols, - const TBDGenOptions &opts) { - assert(symbols.empty() && "Additive symbol enumeration not supported"); - auto &evaluator = file->getASTContext().evaluator; - auto desc = TBDGenDescriptor::forFile(file, opts); - symbols = llvm::cantFail(evaluator(GenerateTBDRequest{desc})).second; -} -void swift::enumeratePublicSymbols(ModuleDecl *M, StringSet &symbols, - const TBDGenOptions &opts) { - assert(symbols.empty() && "Additive symbol enumeration not supported"); - auto &evaluator = M->getASTContext().evaluator; - auto desc = TBDGenDescriptor::forModule(M, opts); - symbols = llvm::cantFail(evaluator(GenerateTBDRequest{desc})).second; +StringSet swift::getPublicSymbols(TBDGenDescriptor desc) { + auto &evaluator = desc.getParentModule()->getASTContext().evaluator; + return llvm::cantFail(evaluator(GenerateTBDRequest{desc})).second; } void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os, const TBDGenOptions &opts) { From 31c1cc26ea87e6e7186743c466dda077a7c55f84 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 13 Jul 2020 20:42:53 -0700 Subject: [PATCH 020/663] Have performParallelIRGeneration take an IRGenDescriptor (cherry picked from commit 01e24a5a1022b9875205db1aa94d2195ef67ac7f) --- lib/IRGen/IRGen.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 2f9d160152144..b7325ddfe6569 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -1103,11 +1103,11 @@ struct LLVMCodeGenThreads { /// Generates LLVM IR, runs the LLVM passes and produces the output files. /// All this is done in multiple threads. -static void performParallelIRGeneration( - const IRGenOptions &Opts, swift::ModuleDecl *M, std::unique_ptr SILMod, - StringRef ModuleName, - ArrayRef outputFilenames, - llvm::StringSet<> *linkerDirectives) { +static void performParallelIRGeneration(IRGenDescriptor desc) { + const auto &Opts = desc.Opts; + auto outputFilenames = desc.parallelOutputFilenames; + auto SILMod = std::unique_ptr(desc.SILMod); + auto *M = desc.getParentModule(); IRGenerator irgen(Opts, *SILMod); @@ -1148,7 +1148,7 @@ static void performParallelIRGeneration( // Create the IR emitter. IRGenModule *IGM = new IRGenModule(irgen, std::move(targetMachine), nextSF, - ModuleName, *OutputIter++, nextSF->getFilename(), + desc.ModuleName, *OutputIter++, nextSF->getFilename(), nextSF->getPrivateDiscriminator().str()); IGMcreated = true; @@ -1168,7 +1168,7 @@ static void performParallelIRGeneration( } // Emit the module contents. - irgen.emitGlobalTopLevel(linkerDirectives); + irgen.emitGlobalTopLevel(desc.LinkerDirectives); for (auto *File : M->getFiles()) { if (auto *SF = dyn_cast(File)) { @@ -1301,18 +1301,17 @@ GeneratedModule swift::performIRGeneration( const PrimarySpecificPaths &PSPs, ArrayRef parallelOutputFilenames, llvm::GlobalVariable **outModuleHash, llvm::StringSet<> *LinkerDirectives) { + auto desc = IRGenDescriptor::forWholeModule( + Opts, M, std::move(SILMod), ModuleName, PSPs, parallelOutputFilenames, + outModuleHash, LinkerDirectives); + if (Opts.shouldPerformIRGenerationInParallel() && !parallelOutputFilenames.empty()) { - ::performParallelIRGeneration(Opts, M, std::move(SILMod), ModuleName, - parallelOutputFilenames, LinkerDirectives); + ::performParallelIRGeneration(desc); // TODO: Parallel LLVM compilation cannot be used if a (single) module is // needed as return value. return GeneratedModule::null(); } - - auto desc = IRGenDescriptor::forWholeModule( - Opts, M, std::move(SILMod), ModuleName, PSPs, parallelOutputFilenames, - outModuleHash, LinkerDirectives); return llvm::cantFail(M->getASTContext().evaluator(IRGenRequest{desc})); } From 4daeb4fa3a2218121b66c4abeff5902cc26e50f9 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 13 Jul 2020 20:42:54 -0700 Subject: [PATCH 021/663] Sink linker directive computation into IRGen With an inverted pipeline, IRGen needs to be able to compute the linker directives itself, so sink it down such that it can be computed by the `IRGenDescriptor`. (cherry picked from commit c0a2ea7d0ea62f64d4000d350162e83b4f22a388) --- include/swift/AST/IRGenRequests.h | 42 ++++++++++++++++++------------- include/swift/Subsystems.h | 13 +++++----- lib/FrontendTool/FrontendTool.cpp | 37 ++++++--------------------- lib/IRGen/CMakeLists.txt | 3 ++- lib/IRGen/GenDecl.cpp | 9 +++---- lib/IRGen/IRGen.cpp | 28 ++++++++++----------- lib/IRGen/IRGenModule.h | 2 +- lib/IRGen/IRGenRequests.cpp | 12 +++++++++ lib/Immediate/Immediate.cpp | 5 ++-- tools/sil-llvm-gen/SILLLVMGen.cpp | 4 ++- 10 files changed, 78 insertions(+), 77 deletions(-) diff --git a/include/swift/AST/IRGenRequests.h b/include/swift/AST/IRGenRequests.h index 3887d8f8dca7c..b6ea1a40c0a1f 100644 --- a/include/swift/AST/IRGenRequests.h +++ b/include/swift/AST/IRGenRequests.h @@ -27,6 +27,7 @@ namespace swift { class SourceFile; class IRGenOptions; class SILModule; +struct TBDGenOptions; namespace irgen { class IRGenModule; @@ -113,15 +114,17 @@ class GeneratedModule final { }; struct IRGenDescriptor { - const IRGenOptions &Opts; llvm::PointerUnion Ctx; + + const IRGenOptions &Opts; + const TBDGenOptions &TBDOpts; + SILModule *SILMod; StringRef ModuleName; const PrimarySpecificPaths &PSPs; StringRef PrivateDiscriminator; ArrayRef parallelOutputFilenames; llvm::GlobalVariable **outModuleHash; - llvm::StringSet<> *LinkerDirectives; friend llvm::hash_code hash_value(const IRGenDescriptor &owner) { return llvm::hash_combine(owner.Ctx); @@ -139,38 +142,38 @@ struct IRGenDescriptor { public: static IRGenDescriptor - forFile(const IRGenOptions &Opts, SourceFile &SF, - std::unique_ptr &&SILMod, StringRef ModuleName, - const PrimarySpecificPaths &PSPs, StringRef PrivateDiscriminator, - llvm::GlobalVariable **outModuleHash, - llvm::StringSet<> *LinkerDirectives) { - return IRGenDescriptor{Opts, - &SF, + forFile(SourceFile &SF, const IRGenOptions &Opts, + const TBDGenOptions &TBDOpts, std::unique_ptr &&SILMod, + StringRef ModuleName, const PrimarySpecificPaths &PSPs, + StringRef PrivateDiscriminator, + llvm::GlobalVariable **outModuleHash) { + return IRGenDescriptor{&SF, + Opts, + TBDOpts, SILMod.release(), ModuleName, PSPs, PrivateDiscriminator, {}, - outModuleHash, - LinkerDirectives}; + outModuleHash}; } static IRGenDescriptor - forWholeModule(const IRGenOptions &Opts, swift::ModuleDecl *M, + forWholeModule(ModuleDecl *M, const IRGenOptions &Opts, + const TBDGenOptions &TBDOpts, std::unique_ptr &&SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, ArrayRef parallelOutputFilenames, - llvm::GlobalVariable **outModuleHash, - llvm::StringSet<> *LinkerDirectives) { - return IRGenDescriptor{Opts, - M, + llvm::GlobalVariable **outModuleHash) { + return IRGenDescriptor{M, + Opts, + TBDOpts, SILMod.release(), ModuleName, PSPs, "", parallelOutputFilenames, - outModuleHash, - LinkerDirectives}; + outModuleHash}; } /// Retrieves the files to perform IR generation for. @@ -179,6 +182,9 @@ struct IRGenDescriptor { /// For a single file, returns its parent module, otherwise returns the module /// itself. ModuleDecl *getParentModule() const; + + /// Compute the linker directives to emit. + llvm::StringSet<> getLinkerDirectives() const; }; /// Report that a request of the given kind is being evaluated, so it diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 09f746dfe1d7e..2275e8735f938 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -62,6 +62,7 @@ namespace swift { class SourceManager; class SyntaxParseActions; class SyntaxParsingCache; + struct TBDGenOptions; class Token; class TopLevelContext; class TypeCheckerOptions; @@ -207,23 +208,23 @@ namespace swift { /// and return the generated LLVM IR module. /// If you set an outModuleHash, then you need to call performLLVM. GeneratedModule - performIRGeneration(const IRGenOptions &Opts, ModuleDecl *M, + performIRGeneration(ModuleDecl *M, const IRGenOptions &Opts, + const TBDGenOptions &TBDOpts, std::unique_ptr SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, ArrayRef parallelOutputFilenames, - llvm::GlobalVariable **outModuleHash = nullptr, - llvm::StringSet<> *LinkerDirectives = nullptr); + llvm::GlobalVariable **outModuleHash = nullptr); /// Turn the given Swift module into either LLVM IR or native code /// and return the generated LLVM IR module. /// If you set an outModuleHash, then you need to call performLLVM. GeneratedModule - performIRGeneration(const IRGenOptions &Opts, SourceFile &SF, + performIRGeneration(SourceFile &SF, const IRGenOptions &Opts, + const TBDGenOptions &TBDOpts, std::unique_ptr SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, StringRef PrivateDiscriminator, - llvm::GlobalVariable **outModuleHash = nullptr, - llvm::StringSet<> *LinkerDirectives = nullptr); + llvm::GlobalVariable **outModuleHash = nullptr); /// Given an already created LLVM module, construct a pass pipeline and run /// the Swift LLVM Pipeline upon it. This does not cause the module to be diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index b08c488226992..817c7d48b8362 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1500,24 +1500,21 @@ static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, } static GeneratedModule -generateIR(const IRGenOptions &IRGenOpts, +generateIR(const IRGenOptions &IRGenOpts, const TBDGenOptions &TBDOpts, std::unique_ptr SM, const PrimarySpecificPaths &PSPs, StringRef OutputFilename, ModuleOrSourceFile MSF, llvm::GlobalVariable *&HashGlobal, - ArrayRef parallelOutputFilenames, - llvm::StringSet<> &LinkerDirectives) { + ArrayRef parallelOutputFilenames) { if (auto *SF = MSF.dyn_cast()) { - return performIRGeneration(IRGenOpts, *SF, + return performIRGeneration(*SF, IRGenOpts, TBDOpts, std::move(SM), OutputFilename, PSPs, SF->getPrivateDiscriminator().str(), - &HashGlobal, - &LinkerDirectives); + &HashGlobal); } else { - return performIRGeneration(IRGenOpts, MSF.get(), + return performIRGeneration(MSF.get(), IRGenOpts, TBDOpts, std::move(SM), OutputFilename, PSPs, - parallelOutputFilenames, - &HashGlobal, &LinkerDirectives); + parallelOutputFilenames, &HashGlobal); } } @@ -1662,19 +1659,6 @@ static bool generateCode(CompilerInstance &Instance, StringRef OutputFilename, OutputFilename, Instance.getStatsReporter()); } -static llvm::StringSet<> -collectLinkerDirectives(const CompilerInvocation &Invocation, - ModuleOrSourceFile MSF) { - auto tbdOpts = Invocation.getTBDGenOptions(); - tbdOpts.LinkerDirectivesOnly = true; - if (auto *SF = MSF.dyn_cast()) { - return getPublicSymbols(TBDGenDescriptor::forFile(SF, tbdOpts)); - } else { - return getPublicSymbols( - TBDGenDescriptor::forModule(MSF.get(), tbdOpts)); - } -} - static bool performCompileStepsPostSILGen(CompilerInstance &Instance, std::unique_ptr SM, ModuleOrSourceFile MSF, @@ -1782,18 +1766,13 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance, return processCommandLineAndRunImmediately( Instance, std::move(SM), MSF, observer, ReturnValue); - llvm::StringSet<> LinkerDirectives; - collectLinkerDirectives(Invocation, MSF, LinkerDirectives); - // Don't proceed to IRGen if collecting linker directives failed. - if (Context.hadError()) - return true; StringRef OutputFilename = PSPs.OutputFilename; std::vector ParallelOutputFilenames = opts.InputsAndOutputs.copyOutputFilenames(); llvm::GlobalVariable *HashGlobal; auto IRModule = generateIR( - IRGenOpts, std::move(SM), PSPs, OutputFilename, MSF, HashGlobal, - ParallelOutputFilenames, LinkerDirectives); + IRGenOpts, Invocation.getTBDGenOptions(), std::move(SM), PSPs, + OutputFilename, MSF, HashGlobal, ParallelOutputFilenames); // Just because we had an AST error it doesn't mean we can't performLLVM. bool HadError = Instance.getASTContext().hadError(); diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index 1e73fff73d49b..7cfe61b987e86 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -69,4 +69,5 @@ target_link_libraries(swiftIRGen PRIVATE swiftLLVMPasses swiftSIL swiftSILGen - swiftSILOptimizer) + swiftSILOptimizer + swiftTBDGen) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 317de350c5370..b8438ad42dfd0 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1027,7 +1027,8 @@ static bool hasCodeCoverageInstrumentation(SILFunction &f, SILModule &m) { return f.getProfiler() && m.getOptions().EmitProfileCoverageMapping; } -void IRGenerator::emitGlobalTopLevel(llvm::StringSet<> *linkerDirectives) { +void IRGenerator::emitGlobalTopLevel( + const llvm::StringSet<> &linkerDirectives) { // Generate order numbers for the functions in the SIL module that // correspond to definitions in the LLVM module. unsigned nextOrderNumber = 0; @@ -1047,10 +1048,8 @@ void IRGenerator::emitGlobalTopLevel(llvm::StringSet<> *linkerDirectives) { CurrentIGMPtr IGM = getGenModule(wt.getProtocol()->getDeclContext()); ensureRelativeSymbolCollocation(wt); } - if (linkerDirectives) { - for (auto &entry: *linkerDirectives) { - createLinkerDirectiveVariable(*PrimaryIGM, entry.getKey()); - } + for (auto &entry: linkerDirectives) { + createLinkerDirectiveVariable(*PrimaryIGM, entry.getKey()); } for (SILGlobalVariable &v : PrimaryIGM->getSILModule().getSILGlobals()) { Decl *decl = v.getDecl(); diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index b7325ddfe6569..366b8e60a1305 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -921,7 +921,7 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator, FrontendStatsTracer tracer(Ctx.Stats, "IRGen"); // Emit the module contents. - irgen.emitGlobalTopLevel(desc.LinkerDirectives); + irgen.emitGlobalTopLevel(desc.getLinkerDirectives()); for (auto *file : filesToEmit) { if (auto *nextSF = dyn_cast(file)) { @@ -1168,7 +1168,7 @@ static void performParallelIRGeneration(IRGenDescriptor desc) { } // Emit the module contents. - irgen.emitGlobalTopLevel(desc.LinkerDirectives); + irgen.emitGlobalTopLevel(desc.getLinkerDirectives()); for (auto *File : M->getFiles()) { if (auto *SF = dyn_cast(File)) { @@ -1296,14 +1296,14 @@ static void performParallelIRGeneration(IRGenDescriptor desc) { } GeneratedModule swift::performIRGeneration( - const IRGenOptions &Opts, swift::ModuleDecl *M, - std::unique_ptr SILMod, StringRef ModuleName, - const PrimarySpecificPaths &PSPs, + swift::ModuleDecl *M, const IRGenOptions &Opts, + const TBDGenOptions &TBDOpts, std::unique_ptr SILMod, + StringRef ModuleName, const PrimarySpecificPaths &PSPs, ArrayRef parallelOutputFilenames, - llvm::GlobalVariable **outModuleHash, llvm::StringSet<> *LinkerDirectives) { + llvm::GlobalVariable **outModuleHash) { auto desc = IRGenDescriptor::forWholeModule( - Opts, M, std::move(SILMod), ModuleName, PSPs, parallelOutputFilenames, - outModuleHash, LinkerDirectives); + M, Opts, TBDOpts, std::move(SILMod), ModuleName, PSPs, + parallelOutputFilenames, outModuleHash); if (Opts.shouldPerformIRGenerationInParallel() && !parallelOutputFilenames.empty()) { @@ -1316,15 +1316,15 @@ GeneratedModule swift::performIRGeneration( } GeneratedModule swift:: -performIRGeneration(const IRGenOptions &Opts, SourceFile &SF, +performIRGeneration(SourceFile &SF, const IRGenOptions &Opts, + const TBDGenOptions &TBDOpts, std::unique_ptr SILMod, StringRef ModuleName, const PrimarySpecificPaths &PSPs, StringRef PrivateDiscriminator, - llvm::GlobalVariable **outModuleHash, - llvm::StringSet<> *LinkerDirectives) { - auto desc = IRGenDescriptor::forFile(Opts, SF, std::move(SILMod), ModuleName, - PSPs, PrivateDiscriminator, - outModuleHash, LinkerDirectives); + llvm::GlobalVariable **outModuleHash) { + auto desc = IRGenDescriptor::forFile(SF, Opts, TBDOpts, std::move(SILMod), + ModuleName, PSPs, PrivateDiscriminator, + outModuleHash); return llvm::cantFail(SF.getASTContext().evaluator(IRGenRequest{desc})); } diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 19485b72bceae..bdda9dec2e742 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -374,7 +374,7 @@ class IRGenerator { /// Emit functions, variables and tables which are needed anyway, e.g. because /// they are externally visible. - void emitGlobalTopLevel(llvm::StringSet<> *LinkerDirectives); + void emitGlobalTopLevel(const llvm::StringSet<> &LinkerDirectives); /// Emit references to each of the protocol descriptors defined in this /// IR module. diff --git a/lib/IRGen/IRGenRequests.cpp b/lib/IRGen/IRGenRequests.cpp index 0bb8963b44984..fa60d83945ec0 100644 --- a/lib/IRGen/IRGenRequests.cpp +++ b/lib/IRGen/IRGenRequests.cpp @@ -17,6 +17,7 @@ #include "swift/AST/SourceFile.h" #include "swift/SIL/SILModule.h" #include "swift/Subsystems.h" +#include "swift/TBDGen/TBDGen.h" #include "llvm/IR/Module.h" #include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" @@ -75,6 +76,17 @@ ModuleDecl *IRGenDescriptor::getParentModule() const { return Ctx.get(); } +llvm::StringSet<> IRGenDescriptor::getLinkerDirectives() const { + auto opts = TBDOpts; + opts.LinkerDirectivesOnly = true; + if (auto *SF = Ctx.dyn_cast()) { + return getPublicSymbols(TBDGenDescriptor::forFile(SF, opts)); + } else { + auto *M = Ctx.get(); + return getPublicSymbols(TBDGenDescriptor::forModule(M, opts)); + } +} + evaluator::DependencySource IRGenRequest::readDependencySource( const evaluator::DependencyRecorder &e) const { auto &desc = std::get<0>(getStorage()); diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp index 3ee13bfd31e3a..d3d2f0ecde675 100644 --- a/lib/Immediate/Immediate.cpp +++ b/lib/Immediate/Immediate.cpp @@ -201,9 +201,10 @@ int swift::RunImmediately(CompilerInstance &CI, // IRGen the main module. auto *swiftModule = CI.getMainModule(); const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary(); + const auto &TBDOpts = CI.getInvocation().getTBDGenOptions(); auto GenModule = performIRGeneration( - IRGenOpts, swiftModule, std::move(SM), swiftModule->getName().str(), - PSPs, ArrayRef()); + swiftModule, IRGenOpts, TBDOpts, std::move(SM), + swiftModule->getName().str(), PSPs, ArrayRef()); if (Context.hadError()) return -1; diff --git a/tools/sil-llvm-gen/SILLLVMGen.cpp b/tools/sil-llvm-gen/SILLLVMGen.cpp index 88f7a897292e1..d444459fb0eb1 100644 --- a/tools/sil-llvm-gen/SILLLVMGen.cpp +++ b/tools/sil-llvm-gen/SILLLVMGen.cpp @@ -204,7 +204,9 @@ int main(int argc, char **argv) { } const PrimarySpecificPaths PSPs(OutputFilename, InputFilename); - auto Mod = performIRGeneration(Opts, CI.getMainModule(), std::move(SILMod), + auto Mod = performIRGeneration(CI.getMainModule(), Opts, + CI.getInvocation().getTBDGenOptions(), + std::move(SILMod), CI.getMainModule()->getName().str(), PSPs, ArrayRef()); return CI.getASTContext().hadError(); From 9b2bcd13f903cca5992f9a41cc6de31a8f81cd33 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 13 Jul 2020 20:42:54 -0700 Subject: [PATCH 022/663] [TBDGen] Return a vector of symbols instead of set A couple of clients are iterating over the result, so switch to a vector to ensure we don't accidentally introduce any non-determinism. (cherry picked from commit 56929fdaaa193cc42d00e3b1a969e1df7aa92875) --- include/swift/AST/IRGenRequests.h | 2 +- include/swift/AST/TBDGenRequests.h | 2 +- include/swift/TBDGen/TBDGen.h | 2 +- lib/FrontendTool/FrontendTool.cpp | 2 +- lib/FrontendTool/TBD.cpp | 26 ++++++++++++++------------ lib/IRGen/GenDecl.cpp | 6 +++--- lib/IRGen/IRGenModule.h | 2 +- lib/IRGen/IRGenRequests.cpp | 2 +- lib/TBDGen/TBDGen.cpp | 20 +++++++++++--------- lib/TBDGen/TBDGenVisitor.h | 15 ++++++++++----- test/TBD/linker-directives.swift | 2 +- 11 files changed, 45 insertions(+), 36 deletions(-) diff --git a/include/swift/AST/IRGenRequests.h b/include/swift/AST/IRGenRequests.h index b6ea1a40c0a1f..67d3117e36215 100644 --- a/include/swift/AST/IRGenRequests.h +++ b/include/swift/AST/IRGenRequests.h @@ -184,7 +184,7 @@ struct IRGenDescriptor { ModuleDecl *getParentModule() const; /// Compute the linker directives to emit. - llvm::StringSet<> getLinkerDirectives() const; + std::vector getLinkerDirectives() const; }; /// Report that a request of the given kind is being evaluated, so it diff --git a/include/swift/AST/TBDGenRequests.h b/include/swift/AST/TBDGenRequests.h index d6e781c20b639..e7c898ece5122 100644 --- a/include/swift/AST/TBDGenRequests.h +++ b/include/swift/AST/TBDGenRequests.h @@ -78,7 +78,7 @@ void simple_display(llvm::raw_ostream &out, const TBDGenDescriptor &desc); SourceLoc extractNearestSourceLoc(const TBDGenDescriptor &desc); using TBDFileAndSymbols = - std::pair>; + std::pair>; /// Computes the TBD file and public symbols for a given module or file. class GenerateTBDRequest diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 67863bb949021..f4d67280b92ec 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -89,7 +89,7 @@ struct TBDGenOptions { } }; -llvm::StringSet<> getPublicSymbols(TBDGenDescriptor desc); +std::vector getPublicSymbols(TBDGenDescriptor desc); void writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os, const TBDGenOptions &opts); diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 817c7d48b8362..4ff8daddc9152 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1073,7 +1073,7 @@ static bool writeLdAddCFileIfNeeded(CompilerInstance &Instance) { llvm::raw_svector_ostream NameOS(NameBuffer); NameOS << "ldAdd_" << Idx; OS << "extern const char " << NameOS.str() << " __asm(\"" << - changeToLdAdd(S.getKey()) << "\");\n"; + changeToLdAdd(S) << "\");\n"; OS << "const char " << NameOS.str() << " = 0;\n"; ++ Idx; } diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp index 5697ddf0a41e9..77a27a2152e87 100644 --- a/lib/FrontendTool/TBD.cpp +++ b/lib/FrontendTool/TBD.cpp @@ -73,10 +73,13 @@ bool swift::inputFileKindCanHaveTBDValidated(InputFileKind kind) { llvm_unreachable("unhandled kind"); } -static bool validateSymbolSet(DiagnosticEngine &diags, - llvm::StringSet<> symbols, - const llvm::Module &IRModule, - bool diagnoseExtraSymbolsInTBD) { +static bool validateSymbols(DiagnosticEngine &diags, + const std::vector &symbols, + const llvm::Module &IRModule, + bool diagnoseExtraSymbolsInTBD) { + llvm::StringSet<> symbolSet; + symbolSet.insert(symbols.begin(), symbols.end()); + auto error = false; // Diff the two sets of symbols, flagging anything outside their intersection. @@ -101,13 +104,13 @@ static bool validateSymbolSet(DiagnosticEngine &diags, GV->hasExternalLinkage() && !GV->hasHiddenVisibility(); if (!GV->isDeclaration() && externallyVisible) { // Is it listed? - if (!symbols.erase(name)) + if (!symbolSet.erase(name)) // Note: Add the unmangled name to the irNotTBD list, which is owned // by the IRModule, instead of the mangled name. irNotTBD.push_back(unmangledName); } } else { - assert(symbols.find(name) == symbols.end() && + assert(symbolSet.find(name) == symbolSet.end() && "non-global value in value symbol table"); } } @@ -121,7 +124,7 @@ static bool validateSymbolSet(DiagnosticEngine &diags, if (diagnoseExtraSymbolsInTBD) { // Look for any extra symbols. - for (auto &name : sortSymbols(symbols)) { + for (auto &name : sortSymbols(symbolSet)) { diags.diagnose(SourceLoc(), diag::symbol_in_tbd_not_in_ir, name, Demangle::demangleSymbolAsString(name)); error = true; @@ -140,8 +143,8 @@ bool swift::validateTBD(ModuleDecl *M, const TBDGenOptions &opts, bool diagnoseExtraSymbolsInTBD) { auto symbols = getPublicSymbols(TBDGenDescriptor::forModule(M, opts)); - return validateSymbolSet(M->getASTContext().Diags, symbols, IRModule, - diagnoseExtraSymbolsInTBD); + return validateSymbols(M->getASTContext().Diags, symbols, IRModule, + diagnoseExtraSymbolsInTBD); } bool swift::validateTBD(FileUnit *file, @@ -149,7 +152,6 @@ bool swift::validateTBD(FileUnit *file, const TBDGenOptions &opts, bool diagnoseExtraSymbolsInTBD) { auto symbols = getPublicSymbols(TBDGenDescriptor::forFile(file, opts)); - return validateSymbolSet(file->getParentModule()->getASTContext().Diags, - symbols, IRModule, - diagnoseExtraSymbolsInTBD); + return validateSymbols(file->getParentModule()->getASTContext().Diags, + symbols, IRModule, diagnoseExtraSymbolsInTBD); } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index b8438ad42dfd0..6683bcfc2c1f8 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1028,7 +1028,7 @@ static bool hasCodeCoverageInstrumentation(SILFunction &f, SILModule &m) { } void IRGenerator::emitGlobalTopLevel( - const llvm::StringSet<> &linkerDirectives) { + const std::vector &linkerDirectives) { // Generate order numbers for the functions in the SIL module that // correspond to definitions in the LLVM module. unsigned nextOrderNumber = 0; @@ -1048,8 +1048,8 @@ void IRGenerator::emitGlobalTopLevel( CurrentIGMPtr IGM = getGenModule(wt.getProtocol()->getDeclContext()); ensureRelativeSymbolCollocation(wt); } - for (auto &entry: linkerDirectives) { - createLinkerDirectiveVariable(*PrimaryIGM, entry.getKey()); + for (auto &directive: linkerDirectives) { + createLinkerDirectiveVariable(*PrimaryIGM, directive); } for (SILGlobalVariable &v : PrimaryIGM->getSILModule().getSILGlobals()) { Decl *decl = v.getDecl(); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index bdda9dec2e742..1ea0b54b31d4f 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -374,7 +374,7 @@ class IRGenerator { /// Emit functions, variables and tables which are needed anyway, e.g. because /// they are externally visible. - void emitGlobalTopLevel(const llvm::StringSet<> &LinkerDirectives); + void emitGlobalTopLevel(const std::vector &LinkerDirectives); /// Emit references to each of the protocol descriptors defined in this /// IR module. diff --git a/lib/IRGen/IRGenRequests.cpp b/lib/IRGen/IRGenRequests.cpp index fa60d83945ec0..5e9f9a7c81851 100644 --- a/lib/IRGen/IRGenRequests.cpp +++ b/lib/IRGen/IRGenRequests.cpp @@ -76,7 +76,7 @@ ModuleDecl *IRGenDescriptor::getParentModule() const { return Ctx.get(); } -llvm::StringSet<> IRGenDescriptor::getLinkerDirectives() const { +std::vector IRGenDescriptor::getLinkerDirectives() const { auto opts = TBDOpts; opts.LinkerDirectivesOnly = true; if (auto *SF = Ctx.dyn_cast()) { diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 8a20be39a2413..92eef52955c5c 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -67,10 +67,14 @@ void TBDGenVisitor::addSymbolInternal(StringRef name, if (!isLinkerDirective && Opts.LinkerDirectivesOnly) return; Symbols.addSymbol(kind, name, Targets); - if (StringSymbols && kind == SymbolKind::GlobalSymbol) { - auto isNewValue = StringSymbols->insert(name).second; - (void)isNewValue; - assert(isNewValue && "symbol appears twice"); + if (kind == SymbolKind::GlobalSymbol) { + StringSymbols.push_back(name); +#ifndef NDEBUG + if (!DuplicateSymbolChecker.insert(name).second) { + llvm::dbgs() << "TBDGen duplicate symbol: " << name << '\n'; + assert(false && "TBDGen symbol appears twice"); + } +#endif } } @@ -1130,10 +1134,8 @@ GenerateTBDRequest::evaluate(Evaluator &evaluator, llvm::MachO::Target targetVar(*ctx.LangOpts.TargetVariant); file.addTarget(targetVar); } - StringSet symbols; auto *clang = static_cast(ctx.getClangModuleLoader()); - TBDGenVisitor visitor(file, {target}, &symbols, - clang->getTargetInfo().getDataLayout(), + TBDGenVisitor visitor(file, {target}, clang->getTargetInfo().getDataLayout(), linkInfo, M, opts); auto visitFile = [&](FileUnit *file) { @@ -1182,10 +1184,10 @@ GenerateTBDRequest::evaluate(Evaluator &evaluator, }); } - return std::make_pair(std::move(file), std::move(symbols)); + return std::make_pair(std::move(file), std::move(visitor.StringSymbols)); } -StringSet swift::getPublicSymbols(TBDGenDescriptor desc) { +std::vector swift::getPublicSymbols(TBDGenDescriptor desc) { auto &evaluator = desc.getParentModule()->getASTContext().evaluator; return llvm::cantFail(evaluator(GenerateTBDRequest{desc})).second; } diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 002f0f8f02414..eb6227b2a417c 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -63,9 +63,14 @@ class TBDGenVisitor : public ASTVisitor { public: llvm::MachO::InterfaceFile &Symbols; llvm::MachO::TargetList Targets; - StringSet *StringSymbols; + std::vector StringSymbols; const llvm::DataLayout &DataLayout; +#ifndef NDEBUG + /// Tracks the symbols emitted to ensure we don't emit any duplicates. + llvm::StringSet<> DuplicateSymbolChecker; +#endif + const UniversalLinkageInfo &UniversalLinkInfo; ModuleDecl *SwiftModule; const TBDGenOptions &Opts; @@ -136,13 +141,13 @@ class TBDGenVisitor : public ASTVisitor { public: TBDGenVisitor(llvm::MachO::InterfaceFile &symbols, - llvm::MachO::TargetList targets, StringSet *stringSymbols, + llvm::MachO::TargetList targets, const llvm::DataLayout &dataLayout, const UniversalLinkageInfo &universalLinkInfo, ModuleDecl *swiftModule, const TBDGenOptions &opts) - : Symbols(symbols), Targets(targets), StringSymbols(stringSymbols), - DataLayout(dataLayout), UniversalLinkInfo(universalLinkInfo), - SwiftModule(swiftModule), Opts(opts), + : Symbols(symbols), Targets(targets), DataLayout(dataLayout), + UniversalLinkInfo(universalLinkInfo), SwiftModule(swiftModule), + Opts(opts), previousInstallNameMap(parsePreviousModuleInstallNameMap()) {} ~TBDGenVisitor() { assert(DeclStack.empty()); } void addMainIfNecessary(FileUnit *file) { diff --git a/test/TBD/linker-directives.swift b/test/TBD/linker-directives.swift index 3e5b9e11c88e0..6a6c5c4eaa23b 100644 --- a/test/TBD/linker-directives.swift +++ b/test/TBD/linker-directives.swift @@ -21,5 +21,5 @@ public func toast() {} // RUN: %target-swift-frontend -typecheck %s -emit-tbd -emit-tbd-path %t/linker_directives.tbd -emit-ldadd-cfile-path %t/ldAdd.c -module-name AppKit // RUN: %FileCheck %s --check-prefix CHECK-C-SYMBOL < %t/ldAdd.c +// CHECK-C-SYMBOL: $ld$add$os10.8$_$s10ToasterKit5toastyyF // CHECK-C-SYMBOL: $ld$add$os10.14$_$s10ToasterKit5toastyyF -// CHECK-C-SYMBOL: $ld$add$os10.8$_$s10ToasterKit5toastyyF \ No newline at end of file From 30de7bda6364e6416cd9c0190a416cc36ed889d8 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 15 Jul 2020 18:03:27 -0700 Subject: [PATCH 023/663] Add missing std::string conversion (cherry picked from commit b0121653560e9fa0191b27eb650dca2329c8164b) --- lib/TBDGen/TBDGen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 92eef52955c5c..e3e4b18df57e8 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -68,7 +68,7 @@ void TBDGenVisitor::addSymbolInternal(StringRef name, return; Symbols.addSymbol(kind, name, Targets); if (kind == SymbolKind::GlobalSymbol) { - StringSymbols.push_back(name); + StringSymbols.push_back(std::string(name)); #ifndef NDEBUG if (!DuplicateSymbolChecker.insert(name).second) { llvm::dbgs() << "TBDGen duplicate symbol: " << name << '\n'; From ff3e2c125d9382828c084de9717fea44b34c222a Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Mon, 20 Jul 2020 16:57:01 -0700 Subject: [PATCH 024/663] [NFC] Use clang::Type->dump() to account for upstream changes. Fixes rdar://65302410. --- lib/AST/Type.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 52ce70d4ea659..12dd1d2df92d3 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3385,12 +3385,10 @@ AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) { #ifndef NDEBUG if (!(type->isFunctionPointerType() || type->isBlockPointerType() || type->isFunctionReferenceType())) { - SmallString<256> buf; - llvm::raw_svector_ostream os(buf); - os << "Expected a Clang function type wrapped in a pointer type or " - << "a block pointer type but found:\n "; - // type->dump(os); - llvm_unreachable(os.str().data()); + llvm::errs() << "Expected a Clang function type wrapped in a pointer type " + << "or a block pointer type but found:\n"; + type->dump(); + llvm_unreachable("\nUnexpected Clang type when creating ExtInfo!"); } #endif return; From a81c5a08861b86a006a28386a036156d9a651a93 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Mon, 20 Jul 2020 17:55:46 -0700 Subject: [PATCH 025/663] Add missing llvm::raw_pwrite_stream forward declaration in swift/Subsystems.h (Build issue) --- include/swift/Subsystems.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index de92b63e176d9..30e057247d53a 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -29,6 +29,7 @@ #include namespace llvm { + class raw_pwrite_stream; class GlobalVariable; class MemoryBuffer; class Module; From 1dd1b5a38afa3158b118f446b2d4f19aa30d179d Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Mon, 20 Jul 2020 18:50:08 -0700 Subject: [PATCH 026/663] Update new code in ModuleInterfaceLoader.cpp for StringRef -> std::string conversion change. --- lib/Frontend/ModuleInterfaceLoader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 81f00c16f74e8..2ca813eed07a2 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -624,7 +624,7 @@ class ModuleInterfaceLoaderImpl { if (shouldLoadAdjacentModule) { if (fs.exists(modulePath)) { - result.first = modulePath; + result.first = modulePath.str(); } } @@ -641,7 +641,7 @@ class ModuleInterfaceLoaderImpl { } if (path) { if (fs.exists(*path)) { - result.second = *path; + result.second = path->str(); } } } From 2b26c221d753b086935dc631495f8d6f0ddc349c Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Mon, 27 Jul 2020 11:00:15 -0700 Subject: [PATCH 027/663] [master-rebranch] Fix up another implicit -> explcit StringRef -> std::string conversion --- lib/FrontendTool/ScanDependencies.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 230b614f844cb..904cd66bd2df1 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -171,7 +171,7 @@ static void discoverCrosssImportOverlayDependencies( dummyMainDependencies.addModuleDependency(modName.str()); mainDep.addModuleDependency(modName.str()); }); - cache.updateDependencies({mainModuleName, ModuleDependenciesKind::Swift}, mainDep); + cache.updateDependencies({mainModuleName.str(), ModuleDependenciesKind::Swift}, mainDep); // Record the dummy main module's direct dependencies. The dummy main module // only directly depend on these newly discovered overlay modules. From e3a2059393c7b3b847fded8565535e447e32bf1c Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Mon, 27 Jul 2020 12:32:52 -0700 Subject: [PATCH 028/663] [master-rebranch] Fix up missing include causing build failures. --- lib/FrontendTool/FrontendTool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 459ca0aaa083b..fb5962ed06c2b 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -67,6 +67,7 @@ #include "swift/TBDGen/TBDGen.h" #include "clang/AST/ASTContext.h" +#include "clang/Basic/Module.h" #include "llvm/ADT/Statistic.h" #include "llvm/IR/LLVMContext.h" From de645d07445b045fe93fddca10c08314215d0be4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 20 Jul 2020 15:31:49 -0700 Subject: [PATCH 029/663] [CSBindings] Make infer* methods private to `PotentialBindings` --- lib/Sema/ConstraintSystem.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index a6c3feb25b7de..6f3dc6d8066e6 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -4582,6 +4582,7 @@ class ConstraintSystem { /// if it has only concrete types or would resolve a closure. bool favoredOverDisjunction(Constraint *disjunction) const; +private: /// Detect `subtype` relationship between two type variables and /// attempt to infer supertype bindings transitively e.g. /// @@ -4604,6 +4605,7 @@ class ConstraintSystem { void inferDefaultTypes(ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes); +public: /// Finalize binding computation for this type variable by /// inferring bindings from context e.g. transitive bindings. void finalize(ConstraintSystem &cs, From fa55358730d7779826f5c5a009ea3e16926a4783 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 20 Jul 2020 16:31:00 -0700 Subject: [PATCH 030/663] [CSBindings] `const` qualify `ConstraintSystem` passed to inference methods --- lib/Sema/CSBindings.cpp | 6 +++--- lib/Sema/ConstraintSystem.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index d6d7187344423..78e7a69048bfa 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -22,7 +22,7 @@ using namespace swift; using namespace constraints; void ConstraintSystem::PotentialBindings::inferTransitiveBindings( - ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes, + const ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes, const llvm::SmallDenseMap &inferredBindings) { @@ -119,7 +119,7 @@ isUnviableDefaultType(Type defaultType, } void ConstraintSystem::PotentialBindings::inferDefaultTypes( - ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes) { + const ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes) { auto isDirectRequirement = [&](Constraint *constraint) -> bool { if (auto *typeVar = constraint->getFirstType()->getAs()) { auto *repr = cs.getRepresentative(typeVar); @@ -275,7 +275,7 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes( } void ConstraintSystem::PotentialBindings::finalize( - ConstraintSystem &cs, + const ConstraintSystem &cs, const llvm::SmallDenseMap &inferredBindings) { diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 6f3dc6d8066e6..6a4df94e465a7 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -4595,20 +4595,21 @@ class ConstraintSystem { /// \param inferredBindings The set of all bindings inferred for type /// variables in the workset. void inferTransitiveBindings( - ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes, + const ConstraintSystem &cs, + llvm::SmallPtrSetImpl &existingTypes, const llvm::SmallDenseMap &inferredBindings); /// Infer bindings based on any protocol conformances that have default /// types. - void inferDefaultTypes(ConstraintSystem &cs, + void inferDefaultTypes(const ConstraintSystem &cs, llvm::SmallPtrSetImpl &existingTypes); public: /// Finalize binding computation for this type variable by /// inferring bindings from context e.g. transitive bindings. - void finalize(ConstraintSystem &cs, + void finalize(const ConstraintSystem &cs, const llvm::SmallDenseMap &inferredBindings); From de390584cd424bc1df96d98dc1f14c65f58eb74b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 22 Jul 2020 13:54:50 -0700 Subject: [PATCH 031/663] [CSBindings] Refactor `getPotentialBindings` into `inferBindingsFor` + `infer` Split `getPotentialBindings` in two: - `inferBindingsFor` should take responsibility for binding constraints to be evaluated as potential binding sources; - `PotentialBindings::infer` would process constraints provided by `inferBindingsFor` and "extract" bindings from them. This is done to separate "sourcing" logic from "inference" and make the former pluggable, so bindings could be computed based on changes in constraint graph in the future. --- lib/Sema/CSBindings.cpp | 463 +++++++++++++++--------------- lib/Sema/ConstraintSystem.h | 9 +- lib/Sema/TypeCheckConstraints.cpp | 2 +- 3 files changed, 248 insertions(+), 226 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 78e7a69048bfa..23e4afe8bd9b3 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -374,7 +374,7 @@ ConstraintSystem::determineBestBindings() { // First, let's collect all of the possible bindings. for (auto *typeVar : getTypeVariables()) { if (!typeVar->getImpl().hasRepresentativeOrFixed()) - cache.insert({typeVar, getPotentialBindings(typeVar)}); + cache.insert({typeVar, inferBindingsFor(typeVar, /*finalize=*/false)}); } // Now let's see if we could infer something for related type @@ -543,12 +543,48 @@ bool ConstraintSystem::PotentialBindings::favoredOverDisjunction( } ConstraintSystem::PotentialBindings -ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar) { - auto bindings = getPotentialBindings(typeVar); +ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar, + bool finalize) const { + assert(typeVar->getImpl().getRepresentative(nullptr) == typeVar && + "not a representative"); + assert(!typeVar->getImpl().getFixedType(nullptr) && "has a fixed type"); + + PotentialBindings bindings(typeVar); + + // Gather the constraints associated with this type variable. + auto constraints = CG.gatherConstraints( + typeVar, ConstraintGraph::GatheringKind::EquivalenceClass); + + llvm::SmallPtrSet exactTypes; + bool hasNonDependentMemberRelationalConstraints = false; + bool hasDependentMemberRelationalConstraints = false; + + for (auto *constraint : constraints) { + bool failed = bindings.infer(*this, exactTypes, constraint, + hasNonDependentMemberRelationalConstraints, + hasDependentMemberRelationalConstraints); + + // Upon inference failure let's produce an empty set of bindings. + if (failed) + return {typeVar}; + } + + // If there were both dependent-member and non-dependent-member relational + // constraints, consider this "fully bound"; we don't want to touch it. + if (hasDependentMemberRelationalConstraints) { + if (hasNonDependentMemberRelationalConstraints) + bindings.FullyBound = true; + else + bindings.Bindings.clear(); + } + + if (finalize) { + llvm::SmallDenseMap + inferred; + + bindings.finalize(*this, inferred); + } - llvm::SmallDenseMap - inferred; - bindings.finalize(*this, inferred); return bindings; } @@ -713,259 +749,238 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( /// Retrieve the set of potential type bindings for the given /// representative type variable, along with flags indicating whether /// those types should be opened. -ConstraintSystem::PotentialBindings -ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { - assert(typeVar->getImpl().getRepresentative(nullptr) == typeVar && - "not a representative"); - assert(!typeVar->getImpl().getFixedType(nullptr) && "has a fixed type"); - +bool ConstraintSystem::PotentialBindings::infer( + const ConstraintSystem &cs, llvm::SmallPtrSetImpl &exactTypes, + Constraint *constraint, bool &hasNonDependentMemberRelationalConstraints, + bool &hasDependentMemberRelationalConstraints) { // Determines whether this type variable represents an object // of the optional type extracted by force unwrap. bool isOptionalObject = false; - if (auto *locator = typeVar->getImpl().getLocator()) { + if (auto *locator = TypeVar->getImpl().getLocator()) { auto anchor = locator->getAnchor(); isOptionalObject = isExpr(anchor); } - // Gather the constraints associated with this type variable. - auto constraints = - getConstraintGraph().gatherConstraints( - typeVar, ConstraintGraph::GatheringKind::EquivalenceClass); - - PotentialBindings result(typeVar); - - // Consider each of the constraints related to this type variable. - llvm::SmallPtrSet exactTypes; SmallVector literalBindings; - bool hasNonDependentMemberRelationalConstraints = false; - bool hasDependentMemberRelationalConstraints = false; - for (auto constraint : constraints) { - switch (constraint->getKind()) { - case ConstraintKind::Bind: - case ConstraintKind::Equal: - case ConstraintKind::BindParam: - case ConstraintKind::BindToPointerType: - case ConstraintKind::Subtype: - case ConstraintKind::Conversion: - case ConstraintKind::ArgumentConversion: - case ConstraintKind::OperatorArgumentConversion: - case ConstraintKind::OptionalObject: { - // If there is a `bind param` constraint associated with - // current type variable, result should be aware of that - // fact. Binding set might be incomplete until - // this constraint is resolved, because we currently don't - // look-through constraints expect to `subtype` to try and - // find related bindings. - // This only affects type variable that appears one the - // right-hand side of the `bind param` constraint and - // represents result type of the closure body, because - // left-hand side gets types from overload choices. - if (constraint->getKind() == ConstraintKind::BindParam && - constraint->getSecondType()->isEqual(typeVar)) - result.PotentiallyIncomplete = true; - - auto binding = getPotentialBindingForRelationalConstraint( - result, constraint, hasDependentMemberRelationalConstraints, - hasNonDependentMemberRelationalConstraints); - if (!binding) - break; - - auto type = binding->BindingType; - if (exactTypes.insert(type->getCanonicalType()).second) { - result.addPotentialBinding(*binding); - - // Result of force unwrap is always connected to its base - // optional type via `OptionalObject` constraint which - // preserves l-valueness, so in case where object type got - // inferred before optional type (because it got the - // type from context e.g. parameter type of a function call), - // we need to test type with and without l-value after - // delaying bindings for as long as possible. - if (isOptionalObject && !type->is()) { - result.addPotentialBinding(binding->withType(LValueType::get(type))); - result.FullyBound = true; - } - - if (auto *locator = typeVar->getImpl().getLocator()) { - auto path = locator->getPath(); - auto voidType = getASTContext().TheEmptyTupleType; - - // If this is a type variable representing closure result, - // which is on the right-side of some relational constraint - // let's have it try `Void` as well because there is an - // implicit conversion `() -> T` to `() -> Void` and this - // helps to avoid creating a thunk to support it. - if (!path.empty() && - path.back().getKind() == ConstraintLocator::ClosureResult && - binding->Kind == AllowedBindingKind::Supertypes && - exactTypes.insert(voidType).second) { - result.addPotentialBinding({voidType, binding->Kind, constraint}, - /*allowJoinMeet=*/false); - } - } - } - break; - } - case ConstraintKind::KeyPathApplication: { - if (result.FullyBound) - continue; - - // If this variable is in the application projected result type, mark the - // result as `FullyBound` to ensure we delay binding until we've bound - // other type variables in the KeyPathApplication constraint. This ensures - // we try to bind the key path type first, which can allow us to discover - // additional bindings for the result type. - SmallPtrSet typeVars; - findInferableTypeVars(simplifyType(constraint->getThirdType()), typeVars); - if (typeVars.count(typeVar)) - result.FullyBound = true; - break; - } + switch (constraint->getKind()) { + case ConstraintKind::Bind: + case ConstraintKind::Equal: + case ConstraintKind::BindParam: + case ConstraintKind::BindToPointerType: + case ConstraintKind::Subtype: + case ConstraintKind::Conversion: + case ConstraintKind::ArgumentConversion: + case ConstraintKind::OperatorArgumentConversion: + case ConstraintKind::OptionalObject: { + // If there is a `bind param` constraint associated with + // current type variable, result should be aware of that + // fact. Binding set might be incomplete until + // this constraint is resolved, because we currently don't + // look-through constraints expect to `subtype` to try and + // find related bindings. + // This only affects type variable that appears one the + // right-hand side of the `bind param` constraint and + // represents result type of the closure body, because + // left-hand side gets types from overload choices. + if (constraint->getKind() == ConstraintKind::BindParam && + constraint->getSecondType()->isEqual(TypeVar)) + PotentiallyIncomplete = true; - case ConstraintKind::BridgingConversion: - case ConstraintKind::CheckedCast: - case ConstraintKind::EscapableFunctionOf: - case ConstraintKind::OpenedExistentialOf: - case ConstraintKind::KeyPath: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: - case ConstraintKind::OpaqueUnderlyingType: - // Constraints from which we can't do anything. + auto binding = cs.getPotentialBindingForRelationalConstraint( + *this, constraint, hasDependentMemberRelationalConstraints, + hasNonDependentMemberRelationalConstraints); + if (!binding) break; - case ConstraintKind::DynamicTypeOf: { - // Direct binding of the left-hand side could result - // in `DynamicTypeOf` failure if right-hand side is - // bound (because 'Bind' requires equal types to - // succeed), or left is bound to Any which is not an - // [existential] metatype. - auto dynamicType = constraint->getFirstType(); - if (auto *tv = dynamicType->getAs()) { - if (tv->getImpl().getRepresentative(nullptr) == typeVar) - return {typeVar}; + auto type = binding->BindingType; + if (exactTypes.insert(type->getCanonicalType()).second) { + addPotentialBinding(*binding); + + // Result of force unwrap is always connected to its base + // optional type via `OptionalObject` constraint which + // preserves l-valueness, so in case where object type got + // inferred before optional type (because it got the + // type from context e.g. parameter type of a function call), + // we need to test type with and without l-value after + // delaying bindings for as long as possible. + if (isOptionalObject && !type->is()) { + addPotentialBinding(binding->withType(LValueType::get(type))); + FullyBound = true; } - // This is right-hand side, let's continue. - break; - } - - case ConstraintKind::Defaultable: - case ConstraintKind::DefaultClosureType: - // Do these in a separate pass. - if (getFixedTypeRecursive(constraint->getFirstType(), true) - ->getAs() == typeVar) { - result.Defaults.push_back(constraint); - hasNonDependentMemberRelationalConstraints = true; + if (auto *locator = TypeVar->getImpl().getLocator()) { + auto path = locator->getPath(); + auto voidType = cs.getASTContext().TheEmptyTupleType; + + // If this is a type variable representing closure result, + // which is on the right-side of some relational constraint + // let's have it try `Void` as well because there is an + // implicit conversion `() -> T` to `() -> Void` and this + // helps to avoid creating a thunk to support it. + if (!path.empty() && + path.back().getKind() == ConstraintLocator::ClosureResult && + binding->Kind == AllowedBindingKind::Supertypes && + exactTypes.insert(voidType).second) { + addPotentialBinding({voidType, binding->Kind, constraint}, + /*allowJoinMeet=*/false); + } } - break; - - case ConstraintKind::Disjunction: - // FIXME: Recurse into these constraints to see whether this - // type variable is fully bound by any of them. - result.InvolvesTypeVariables = true; - - // If there is additional context available via disjunction - // associated with closure literal (e.g. coercion to some other - // type) let's delay resolving the closure until the disjunction - // is attempted. - if (typeVar->getImpl().isClosureType()) - return {typeVar}; - - break; + } + break; + } + case ConstraintKind::KeyPathApplication: { + if (FullyBound) + return false; + + // If this variable is in the application projected result type, mark the + // result as `FullyBound` to ensure we delay binding until we've bound + // other type variables in the KeyPathApplication constraint. This ensures + // we try to bind the key path type first, which can allow us to discover + // additional bindings for the result type. + SmallPtrSet typeVars; + findInferableTypeVars(cs.simplifyType(constraint->getThirdType()), + typeVars); + if (typeVars.count(TypeVar)) + FullyBound = true; - case ConstraintKind::ConformsTo: - case ConstraintKind::SelfObjectOfProtocol: - // Swift 3 allowed the use of default types for normal conformances - // to expressible-by-literal protocols. - if (getASTContext().LangOpts.EffectiveLanguageVersion[0] >= 4) - continue; + break; + } - if (!constraint->getSecondType()->is()) - continue; + case ConstraintKind::BridgingConversion: + case ConstraintKind::CheckedCast: + case ConstraintKind::EscapableFunctionOf: + case ConstraintKind::OpenedExistentialOf: + case ConstraintKind::KeyPath: + case ConstraintKind::FunctionInput: + case ConstraintKind::FunctionResult: + case ConstraintKind::OpaqueUnderlyingType: + // Constraints from which we can't do anything. + break; + + case ConstraintKind::DynamicTypeOf: { + // Direct binding of the left-hand side could result + // in `DynamicTypeOf` failure if right-hand side is + // bound (because 'Bind' requires equal types to + // succeed), or left is bound to Any which is not an + // [existential] metatype. + auto dynamicType = constraint->getFirstType(); + if (auto *tv = dynamicType->getAs()) { + if (tv->getImpl().getRepresentative(nullptr) == TypeVar) + return true; + } - LLVM_FALLTHROUGH; + // This is right-hand side, let's continue. + break; + } - case ConstraintKind::LiteralConformsTo: { - // Record constraint where protocol requirement originated - // this is useful to use for the binding later. - result.Protocols.push_back(constraint); + case ConstraintKind::Defaultable: + case ConstraintKind::DefaultClosureType: + // Do these in a separate pass. + if (cs.getFixedTypeRecursive(constraint->getFirstType(), true) + ->getAs() == TypeVar) { + Defaults.push_back(constraint); hasNonDependentMemberRelationalConstraints = true; - break; } + break; + + case ConstraintKind::Disjunction: + // FIXME: Recurse into these constraints to see whether this + // type variable is fully bound by any of them. + InvolvesTypeVariables = true; + + // If there is additional context available via disjunction + // associated with closure literal (e.g. coercion to some other + // type) let's delay resolving the closure until the disjunction + // is attempted. + if (TypeVar->getImpl().isClosureType()) + return true; - case ConstraintKind::ApplicableFunction: - case ConstraintKind::DynamicCallableApplicableFunction: - case ConstraintKind::BindOverload: { - if (result.FullyBound && result.InvolvesTypeVariables) - continue; + break; - // If this variable is in the left-hand side, it is fully bound. - SmallPtrSet typeVars; - findInferableTypeVars(simplifyType(constraint->getFirstType()), typeVars); - if (typeVars.count(typeVar)) - result.FullyBound = true; + case ConstraintKind::ConformsTo: + case ConstraintKind::SelfObjectOfProtocol: + // Swift 3 allowed the use of default types for normal conformances + // to expressible-by-literal protocols. + if (cs.getASTContext().LangOpts.EffectiveLanguageVersion[0] >= 4) + return false; - if (result.InvolvesTypeVariables) - continue; + if (!constraint->getSecondType()->is()) + return false; - // If this and another type variable occur, this result involves - // type variables. - findInferableTypeVars(simplifyType(constraint->getSecondType()), - typeVars); - if (typeVars.size() > 1 && typeVars.count(typeVar)) - result.InvolvesTypeVariables = true; + LLVM_FALLTHROUGH; - break; - } + case ConstraintKind::LiteralConformsTo: { + // Record constraint where protocol requirement originated + // this is useful to use for the binding later. + Protocols.push_back(constraint); + hasNonDependentMemberRelationalConstraints = true; + break; + } - case ConstraintKind::ValueMember: - case ConstraintKind::UnresolvedValueMember: - case ConstraintKind::ValueWitness: - // If our type variable shows up in the base type, there's - // nothing to do. - // FIXME: Can we avoid simplification here? - if (ConstraintSystem::typeVarOccursInType( - typeVar, simplifyType(constraint->getFirstType()), - &result.InvolvesTypeVariables)) { - continue; - } + case ConstraintKind::ApplicableFunction: + case ConstraintKind::DynamicCallableApplicableFunction: + case ConstraintKind::BindOverload: { + if (FullyBound && InvolvesTypeVariables) + return false; - // If the type variable is in the list of member type - // variables, it is fully bound. - // FIXME: Can we avoid simplification here? - if (ConstraintSystem::typeVarOccursInType( - typeVar, simplifyType(constraint->getSecondType()), - &result.InvolvesTypeVariables)) { - result.FullyBound = true; - } - break; + // If this variable is in the left-hand side, it is fully bound. + SmallPtrSet typeVars; + findInferableTypeVars(cs.simplifyType(constraint->getFirstType()), + typeVars); + if (typeVars.count(TypeVar)) + FullyBound = true; + + if (InvolvesTypeVariables) + return false; + + // If this and another type variable occur, this result involves + // type variables. + findInferableTypeVars(cs.simplifyType(constraint->getSecondType()), + typeVars); + if (typeVars.size() > 1 && typeVars.count(TypeVar)) + InvolvesTypeVariables = true; + + break; + } - case ConstraintKind::OneWayEqual: - case ConstraintKind::OneWayBindParam: { - // Don't produce any bindings if this type variable is on the left-hand - // side of a one-way binding. - auto firstType = constraint->getFirstType(); - if (auto *tv = firstType->getAs()) { - if (tv->getImpl().getRepresentative(nullptr) == typeVar) - return {typeVar}; - } + case ConstraintKind::ValueMember: + case ConstraintKind::UnresolvedValueMember: + case ConstraintKind::ValueWitness: + // If our type variable shows up in the base type, there's + // nothing to do. + // FIXME: Can we avoid simplification here? + if (ConstraintSystem::typeVarOccursInType( + TypeVar, cs.simplifyType(constraint->getFirstType()), + &InvolvesTypeVariables)) { + return false; + } - break; + // If the type variable is in the list of member type + // variables, it is fully bound. + // FIXME: Can we avoid simplification here? + if (ConstraintSystem::typeVarOccursInType( + TypeVar, cs.simplifyType(constraint->getSecondType()), + &InvolvesTypeVariables)) { + FullyBound = true; } + break; + + case ConstraintKind::OneWayEqual: + case ConstraintKind::OneWayBindParam: { + // Don't produce any bindings if this type variable is on the left-hand + // side of a one-way binding. + auto firstType = constraint->getFirstType(); + if (auto *tv = firstType->getAs()) { + if (tv->getImpl().getRepresentative(nullptr) == TypeVar) + return true; } - } - // If there were both dependent-member and non-dependent-member relational - // constraints, consider this "fully bound"; we don't want to touch it. - if (hasDependentMemberRelationalConstraints) { - if (hasNonDependentMemberRelationalConstraints) - result.FullyBound = true; - else - result.Bindings.clear(); + break; + } } - return result; + return false; } /// Check whether the given type can be used as a binding for the given diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 6a4df94e465a7..7838488f62016 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -4607,6 +4607,12 @@ class ConstraintSystem { llvm::SmallPtrSetImpl &existingTypes); public: + bool infer(const ConstraintSystem &cs, + llvm::SmallPtrSetImpl &exactTypes, + Constraint *constraint, + bool &hasNonDependentMemberRelationalConstraints, + bool &hasDependentMemberRelationalConstraints); + /// Finalize binding computation for this type variable by /// inferring bindings from context e.g. transitive bindings. void finalize(const ConstraintSystem &cs, @@ -4677,7 +4683,8 @@ class ConstraintSystem { /// Infer bindings for the given type variable based on current /// state of the constraint system. - PotentialBindings inferBindingsFor(TypeVariableType *typeVar); + PotentialBindings inferBindingsFor(TypeVariableType *typeVar, + bool finalize = true) const; private: Optional diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 53b82ee7aaeaa..5ab31c3785868 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2945,7 +2945,7 @@ void ConstraintSystem::print(raw_ostream &out) const { out << " as "; Type(fixed).print(out, PO); } else { - getPotentialBindings(tv).dump(out, 1); + inferBindingsFor(tv).dump(out, 1); } } else { out << " equivalent to "; From 99e6cd42f689017aaa4508122db2cb4a82f6929f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 22 Jul 2020 16:13:43 -0700 Subject: [PATCH 032/663] [CSBindings] Modernize and consolidate locator checking for binding adjustment --- lib/Sema/CSBindings.cpp | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 23e4afe8bd9b3..0e865a9e79757 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -753,14 +753,6 @@ bool ConstraintSystem::PotentialBindings::infer( const ConstraintSystem &cs, llvm::SmallPtrSetImpl &exactTypes, Constraint *constraint, bool &hasNonDependentMemberRelationalConstraints, bool &hasDependentMemberRelationalConstraints) { - // Determines whether this type variable represents an object - // of the optional type extracted by force unwrap. - bool isOptionalObject = false; - if (auto *locator = TypeVar->getImpl().getLocator()) { - auto anchor = locator->getAnchor(); - isOptionalObject = isExpr(anchor); - } - SmallVector literalBindings; switch (constraint->getKind()) { @@ -797,29 +789,29 @@ bool ConstraintSystem::PotentialBindings::infer( if (exactTypes.insert(type->getCanonicalType()).second) { addPotentialBinding(*binding); - // Result of force unwrap is always connected to its base - // optional type via `OptionalObject` constraint which - // preserves l-valueness, so in case where object type got - // inferred before optional type (because it got the - // type from context e.g. parameter type of a function call), - // we need to test type with and without l-value after - // delaying bindings for as long as possible. - if (isOptionalObject && !type->is()) { - addPotentialBinding(binding->withType(LValueType::get(type))); - FullyBound = true; - } - + // Determines whether this type variable represents an object + // of the optional type extracted by force unwrap. if (auto *locator = TypeVar->getImpl().getLocator()) { - auto path = locator->getPath(); - auto voidType = cs.getASTContext().TheEmptyTupleType; + auto anchor = locator->getAnchor(); + // Result of force unwrap is always connected to its base + // optional type via `OptionalObject` constraint which + // preserves l-valueness, so in case where object type got + // inferred before optional type (because it got the + // type from context e.g. parameter type of a function call), + // we need to test type with and without l-value after + // delaying bindings for as long as possible. + if (isExpr(anchor) && !type->is()) { + addPotentialBinding(binding->withType(LValueType::get(type))); + FullyBound = true; + } // If this is a type variable representing closure result, // which is on the right-side of some relational constraint // let's have it try `Void` as well because there is an // implicit conversion `() -> T` to `() -> Void` and this // helps to avoid creating a thunk to support it. - if (!path.empty() && - path.back().getKind() == ConstraintLocator::ClosureResult && + auto voidType = cs.getASTContext().TheEmptyTupleType; + if (locator->isLastElement() && binding->Kind == AllowedBindingKind::Supertypes && exactTypes.insert(voidType).second) { addPotentialBinding({voidType, binding->Kind, constraint}, From dff73c946751c901e916754ba4517a132ac45d25 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 22 Jul 2020 16:14:33 -0700 Subject: [PATCH 033/663] [CSBindings] NFC: Remove obsolete `literalBindings` vector --- lib/Sema/CSBindings.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 0e865a9e79757..09cd411c2e48d 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -753,8 +753,6 @@ bool ConstraintSystem::PotentialBindings::infer( const ConstraintSystem &cs, llvm::SmallPtrSetImpl &exactTypes, Constraint *constraint, bool &hasNonDependentMemberRelationalConstraints, bool &hasDependentMemberRelationalConstraints) { - SmallVector literalBindings; - switch (constraint->getKind()) { case ConstraintKind::Bind: case ConstraintKind::Equal: From 587973fd8b31d86e981401be0a3fcd0698b31f20 Mon Sep 17 00:00:00 2001 From: Butta Date: Tue, 28 Jul 2020 12:27:48 +0530 Subject: [PATCH 034/663] [build] Remove unemployed 'skip-{build,test}-*' flags from build-script-impl These flags have done nothing for awhile, as 26 of 31 have already been moved to build-script. Only the flags related to haiku, maccatalyst, and external-benchmarks are unrecognized by either build script after this removal. --- utils/build-script | 55 ----------------------------------------- utils/build-script-impl | 31 ----------------------- 2 files changed, 86 deletions(-) diff --git a/utils/build-script b/utils/build-script index e3ed824f977d9..f92750df7c1a3 100755 --- a/utils/build-script +++ b/utils/build-script @@ -560,9 +560,6 @@ class BuildScriptInvocation(object): impl_args += ["--skip-build"] if not args.build_benchmarks: impl_args += ["--skip-build-benchmarks"] - # Currently we do not build external benchmarks by default. - if args.build_external_benchmarks: - impl_args += ["--skip-build-external-benchmarks=0"] # Then add subproject install flags that either skip building them /or/ # if we are going to build them and install_all is set, we also install @@ -596,26 +593,6 @@ class BuildScriptInvocation(object): if args.build_swift_static_sdk_overlay: impl_args += ["--build-swift-static-sdk-overlay"] - if not args.build_linux: - impl_args += ["--skip-build-linux"] - if not args.build_freebsd: - impl_args += ["--skip-build-freebsd"] - if not args.build_cygwin: - impl_args += ["--skip-build-cygwin"] - if not args.build_osx: - impl_args += ["--skip-build-osx"] - if not args.build_ios_device: - impl_args += ["--skip-build-ios-device"] - if not args.build_ios_simulator: - impl_args += ["--skip-build-ios-simulator"] - if not args.build_tvos_device: - impl_args += ["--skip-build-tvos-device"] - if not args.build_tvos_simulator: - impl_args += ["--skip-build-tvos-simulator"] - if not args.build_watchos_device: - impl_args += ["--skip-build-watchos-device"] - if not args.build_watchos_simulator: - impl_args += ["--skip-build-watchos-simulator"] if not args.build_android: impl_args += ["--skip-build-android"] if not args.build_clang_tools_extra: @@ -633,32 +610,6 @@ class BuildScriptInvocation(object): "--skip-test-libdispatch", "--skip-test-libicu", ] - if not args.test_linux: - impl_args += ["--skip-test-linux"] - if not args.test_freebsd: - impl_args += ["--skip-test-freebsd"] - if not args.test_cygwin: - impl_args += ["--skip-test-cygwin"] - if not args.test_osx: - impl_args += ["--skip-test-osx"] - if not args.test_ios_host: - impl_args += ["--skip-test-ios-host"] - if not args.test_ios_simulator: - impl_args += ["--skip-test-ios-simulator"] - if not args.test_ios_32bit_simulator: - impl_args += ["--skip-test-ios-32bit-simulator"] - if not args.test_tvos_host: - impl_args += ["--skip-test-tvos-host"] - if not args.test_tvos_simulator: - impl_args += ["--skip-test-tvos-simulator"] - if not args.test_watchos_host: - impl_args += ["--skip-test-watchos-host"] - if not args.test_watchos_simulator: - impl_args += ["--skip-test-watchos-simulator"] - if not args.test_android: - impl_args += ["--skip-test-android"] - if not args.test_android_host: - impl_args += ["--skip-test-android-host"] if args.build_runtime_with_host_compiler: impl_args += ["--build-runtime-with-host-compiler"] if args.validation_test: @@ -673,12 +624,6 @@ class BuildScriptInvocation(object): impl_args += ["--only-executable-test"] if not args.benchmark: impl_args += ["--skip-test-benchmarks"] - if not args.test_optimized: - impl_args += ["--skip-test-optimized"] - if not args.test_optimize_for_size: - impl_args += ["--skip-test-optimize-for-size"] - if not args.test_optimize_none_with_implicit_dynamic: - impl_args += ["--skip-test-optimize-none-with-implicit-dynamic"] if args.build_libparser_only: impl_args += ["--build-libparser-only"] if args.android: diff --git a/utils/build-script-impl b/utils/build-script-impl index e3917be0f9a33..7b223c34299cd 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -126,40 +126,9 @@ KNOWN_SETTINGS=( skip-build-clang-tools-extra "" "set to skip building clang-tools-extra as part of llvm" skip-build-compiler-rt "" "set to skip building Compiler-RT" skip-build-lld "" "set to skip building lld as part of llvm (linux only)" - skip-build-cygwin "" "set to skip building Swift stdlibs for Cygwin" - skip-build-external-benchmarks "1" "set to skip building the external Swift Benchmark Suite. (skipped by default)" - skip-build-freebsd "" "set to skip building Swift stdlibs for FreeBSD" - skip-build-haiku "" "set to skip building Swift stdlibs for Haiku" - skip-build-ios-device "" "set to skip building Swift stdlibs for iOS devices (i.e. build simulators only)" - skip-build-ios-simulator "" "set to skip building Swift stdlibs for iOS simulators (i.e. build devices only)" - skip-build-linux "" "set to skip building Swift stdlibs for Linux" - skip-build-maccatalyst "" "set to skip building Swift stdlibs for macCatalyst" - skip-build-osx "" "set to skip building Swift stdlibs for OS X" - skip-build-tvos-device "" "set to skip building Swift stdlibs for tvOS devices (i.e. build simulators only)" - skip-build-tvos-simulator "" "set to skip building Swift stdlibs for tvOS simulators (i.e. build devices only)" - skip-build-watchos-device "" "set to skip building Swift stdlibs for Apple watchOS devices (i.e. build simulators only)" - skip-build-watchos-simulator "" "set to skip building Swift stdlibs for Apple watchOS simulators (i.e. build devices only)" ## Skip Test ... - skip-test-android "" "set to skip testing Swift stdlibs for Android" - skip-test-android-host "" "set to skip testing the host parts of the Android toolchain" - skip-test-cygwin "" "set to skip testing Swift stdlibs for Cygwin" - skip-test-freebsd "" "set to skip testing Swift stdlibs for FreeBSD" - skip-test-haiku "" "set to skip testing Swift stdlibs for Haiku" - skip-test-ios-32bit-simulator "" "set to skip testing Swift stdlibs for iOS 32bit simulators" - skip-test-ios-host "" "set to skip testing the host parts of the iOS toolchain" - skip-test-ios-simulator "" "set to skip testing Swift stdlibs for iOS simulators (i.e. test devices only)" - skip-test-linux "" "set to skip testing Swift stdlibs for Linux" - skip-test-maccatalyst "" "set to skip testing Swift stdlibs for macCatalyst" - skip-test-osx "" "set to skip testing Swift stdlibs for OS X" - skip-test-tvos-host "" "set to skip testing the host parts of the tvOS toolchain" - skip-test-tvos-simulator "" "set to skip testing Swift stdlibs for tvOS simulators (i.e. test devices only)" - skip-test-watchos-host "" "set to skip testing the host parts of the watchOS toolchain" - skip-test-watchos-simulator "" "set to skip testing Swift stdlibs for Apple watchOS simulators (i.e. test devices only)" skip-test-benchmarks "" "set to skip running Swift Benchmark Suite" - skip-test-optimized "" "set to skip testing the test suite in optimized mode" - skip-test-optimize-for-size "" "set to skip testing the test suite in optimize for size mode" - skip-test-optimize-none-with-implicit-dynamic "" "set to skip testing the test suite in optimize none with implicit dynamic mode" skip-test-sourcekit "" "set to skip testing SourceKit" ## Extra ... CMake Options From 6dd859e92f64149bfe74ce0fe3ba5579403a3644 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 28 Jul 2020 12:48:33 -0700 Subject: [PATCH 035/663] [CSBindings] Remove remaining flags from inference --- lib/Sema/CSBindings.cpp | 33 +++++++-------------------------- lib/Sema/ConstraintSystem.h | 10 +++------- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 09cd411c2e48d..f4b3b27363a99 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -556,28 +556,15 @@ ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar, typeVar, ConstraintGraph::GatheringKind::EquivalenceClass); llvm::SmallPtrSet exactTypes; - bool hasNonDependentMemberRelationalConstraints = false; - bool hasDependentMemberRelationalConstraints = false; for (auto *constraint : constraints) { - bool failed = bindings.infer(*this, exactTypes, constraint, - hasNonDependentMemberRelationalConstraints, - hasDependentMemberRelationalConstraints); + bool failed = bindings.infer(*this, exactTypes, constraint); // Upon inference failure let's produce an empty set of bindings. if (failed) return {typeVar}; } - // If there were both dependent-member and non-dependent-member relational - // constraints, consider this "fully bound"; we don't want to touch it. - if (hasDependentMemberRelationalConstraints) { - if (hasNonDependentMemberRelationalConstraints) - bindings.FullyBound = true; - else - bindings.Bindings.clear(); - } - if (finalize) { llvm::SmallDenseMap inferred; @@ -590,9 +577,7 @@ ConstraintSystem::inferBindingsFor(TypeVariableType *typeVar, Optional ConstraintSystem::getPotentialBindingForRelationalConstraint( - PotentialBindings &result, Constraint *constraint, - bool &hasDependentMemberRelationalConstraints, - bool &hasNonDependentMemberRelationalConstraints) const { + PotentialBindings &result, Constraint *constraint) const { assert(constraint->getClassification() == ConstraintClassification::Relational && "only relational constraints handled here"); @@ -675,11 +660,11 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( if (type->is()) { if (!ConstraintSystem::typeVarOccursInType(typeVar, type, &result.InvolvesTypeVariables)) { - hasDependentMemberRelationalConstraints = true; + result.FullyBound = true; } + return None; } - hasNonDependentMemberRelationalConstraints = true; // If our binding choice is a function type and we're attempting // to bind to a type variable that is the result of opening a @@ -751,8 +736,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( /// those types should be opened. bool ConstraintSystem::PotentialBindings::infer( const ConstraintSystem &cs, llvm::SmallPtrSetImpl &exactTypes, - Constraint *constraint, bool &hasNonDependentMemberRelationalConstraints, - bool &hasDependentMemberRelationalConstraints) { + Constraint *constraint) { switch (constraint->getKind()) { case ConstraintKind::Bind: case ConstraintKind::Equal: @@ -777,9 +761,8 @@ bool ConstraintSystem::PotentialBindings::infer( constraint->getSecondType()->isEqual(TypeVar)) PotentiallyIncomplete = true; - auto binding = cs.getPotentialBindingForRelationalConstraint( - *this, constraint, hasDependentMemberRelationalConstraints, - hasNonDependentMemberRelationalConstraints); + auto binding = + cs.getPotentialBindingForRelationalConstraint(*this, constraint); if (!binding) break; @@ -870,7 +853,6 @@ bool ConstraintSystem::PotentialBindings::infer( if (cs.getFixedTypeRecursive(constraint->getFirstType(), true) ->getAs() == TypeVar) { Defaults.push_back(constraint); - hasNonDependentMemberRelationalConstraints = true; } break; @@ -904,7 +886,6 @@ bool ConstraintSystem::PotentialBindings::infer( // Record constraint where protocol requirement originated // this is useful to use for the binding later. Protocols.push_back(constraint); - hasNonDependentMemberRelationalConstraints = true; break; } diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 7838488f62016..91bee5d68d3bb 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -4609,9 +4609,7 @@ class ConstraintSystem { public: bool infer(const ConstraintSystem &cs, llvm::SmallPtrSetImpl &exactTypes, - Constraint *constraint, - bool &hasNonDependentMemberRelationalConstraints, - bool &hasDependentMemberRelationalConstraints); + Constraint *constraint); /// Finalize binding computation for this type variable by /// inferring bindings from context e.g. transitive bindings. @@ -4688,10 +4686,8 @@ class ConstraintSystem { private: Optional - getPotentialBindingForRelationalConstraint( - PotentialBindings &result, Constraint *constraint, - bool &hasDependentMemberRelationalConstraints, - bool &hasNonDependentMemberRelationalConstraints) const; + getPotentialBindingForRelationalConstraint(PotentialBindings &result, + Constraint *constraint) const; PotentialBindings getPotentialBindings(TypeVariableType *typeVar) const; /// Add a constraint to the constraint system. From 774dfbf2af6afb1fd99c197a9f344e1830b798f0 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Tue, 28 Jul 2020 13:17:15 -0700 Subject: [PATCH 036/663] Fix an implicit StringRef -> std::string conversion issue in StringOptimization.cpp --- lib/SILOptimizer/Transforms/StringOptimization.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Transforms/StringOptimization.cpp b/lib/SILOptimizer/Transforms/StringOptimization.cpp index f735d7ab02d55..9b3abf4b393fe 100644 --- a/lib/SILOptimizer/Transforms/StringOptimization.cpp +++ b/lib/SILOptimizer/Transforms/StringOptimization.cpp @@ -187,7 +187,7 @@ bool StringOptimization::optimizeStringAppend(ApplyInst *appendCall, // Replace lhs.append(rhs) with "lhs = lhs + rhs" if both lhs and rhs are // constant. if (lhsString.isConstant() && rhsString.isConstant()) { - std::string concat = lhsString.str; + std::string concat = lhsString.str.str(); concat += rhsString.str; if (ApplyInst *stringInit = createStringInit(concat, appendCall)) { replaceAppendWith(appendCall, stringInit, /*copyNewValue*/ false); From ac4fc647905308defc3ebd989b8db01dd053c205 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Wed, 29 Jul 2020 11:42:52 -0700 Subject: [PATCH 037/663] Fix more StringRef -> std::string conversion build issues --- include/swift/Frontend/ModuleInterfaceLoader.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 0b0e30717a806..6d80cd8b8b99e 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -243,11 +243,11 @@ class ExplicitModuleMapParser { if (key == "moduleName") { moduleName = val; } else if (key == "modulePath") { - result.modulePath = val; + result.modulePath = val.str(); } else if (key == "docPath") { - result.moduleDocPath = val; + result.moduleDocPath = val.str(); } else if (key == "sourceInfoPath") { - result.moduleSourceInfoPath = val; + result.moduleSourceInfoPath = val.str(); } else { // Being forgiving for future fields. continue; From 9406d4613865801b6394b552c94d79417bc90d29 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 23 Jul 2020 14:24:47 -0700 Subject: [PATCH 038/663] [build-preset] Add swift-driver to CI builder presets Build and test the new integrated swift driver against the just-built toolchain --- utils/build-presets.ini | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 9eaa76a841a99..1268aac2ee6e2 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -371,6 +371,7 @@ libcxx # Build llbuild & swiftpm here llbuild swiftpm +swift-driver indexstore-db sourcekit-lsp @@ -396,6 +397,7 @@ install-llvm install-swift install-llbuild install-swiftpm +install-swift-driver install-libcxx [preset: buildbot_incremental,tools=RA,stdlib=RA,xcode] @@ -418,6 +420,7 @@ swift-primary-variant-arch=x86_64 skip-build-llbuild skip-test-llbuild skip-test-swiftpm +skip-test-swift-driver skip-test-playgroundsupport # This preset is used by CI to test swift-corelibs-xctest. @@ -602,12 +605,14 @@ build-ninja libcxx llbuild swiftpm +swift-driver indexstore-db sourcekit-lsp install-llvm install-swift install-llbuild install-swiftpm +install-swift-driver install-libcxx # We need to build the unittest extras so we can test @@ -791,6 +796,7 @@ mixin-preset= llbuild swiftpm +swift-driver xctest libicu libcxx @@ -803,6 +809,7 @@ install-swift install-lldb install-llbuild install-swiftpm +install-swift-driver install-xctest install-libicu install-prefix=/usr @@ -859,6 +866,7 @@ skip-test-lldb skip-test-swift skip-test-llbuild skip-test-swiftpm +skip-test-swift-driver skip-test-xctest skip-test-foundation skip-test-libdispatch @@ -1020,6 +1028,7 @@ lldb #test foundation swiftpm +swift-driver xctest build-subdir=buildbot_linux @@ -1032,6 +1041,7 @@ install-lldb install-llbuild install-foundation install-swiftpm +install-swift-driver install-xctest install-prefix=/usr swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;swift-remote-mirror;sdk-overlay;dev @@ -1079,6 +1089,7 @@ libcxx libicu llbuild swiftpm +swift-driver xctest foundation libdispatch @@ -1092,6 +1103,7 @@ install-swift install-llbuild install-libicu install-swiftpm +install-swift-driver install-foundation install-libdispatch install-xctest @@ -1195,6 +1207,7 @@ watchos lldb llbuild swiftpm +swift-driver swiftsyntax skstresstester swiftevolve @@ -1226,6 +1239,7 @@ install-swift install-lldb install-llbuild install-swiftpm +install-swift-driver install-swiftsyntax install-skstresstester install-swiftevolve @@ -1319,6 +1333,7 @@ dash-dash skip-test-swift skip-test-swiftpm +skip-test-swift-driver skip-test-llbuild skip-test-lldb skip-test-cmark @@ -1350,6 +1365,7 @@ dash-dash skip-test-swift skip-test-swiftpm +skip-test-swift-driver skip-test-llbuild skip-test-lldb skip-test-cmark @@ -1487,6 +1503,7 @@ libcxx # Build llbuild & swiftpm here llbuild swiftpm +swift-driver swiftsyntax # Don't generate the SwiftSyntax gyb files. Instead verify that up-to-date ones @@ -1500,6 +1517,7 @@ install-llvm install-swift install-llbuild install-swiftpm +install-swift-driver install-libcxx # Build the stress tester and SwiftEvolve @@ -1686,6 +1704,22 @@ assertions # Downstream projects that import llbuild+SwiftPM. sourcekit-lsp +#===------------------------------------------------------------------------===# +# Test Swift Driver (new) +#===------------------------------------------------------------------------===# + +[preset: buildbot_swift-driver_macos] +mixin-preset=mixin_swiftpm_package_macos_platform +release +assertions +swift-driver + +[preset: buildbot_swift-driver_linux] +mixin-preset=mixin_swiftpm_package_linux_platform +release +assertions +swift-driver + #===------------------------------------------------------------------------===# # Test Swift Syntax #===------------------------------------------------------------------------===# @@ -2373,10 +2407,12 @@ validation-test build-ninja llbuild swiftpm +swift-driver install-llbuild install-llvm install-swift install-swiftpm +install-swift-driver reconfigure verbose-build skip-build-benchmarks From 3707cfab127aa538511a55ecf2eb903a9572ecde Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Tue, 4 Aug 2020 14:19:15 -0700 Subject: [PATCH 039/663] Fix build failures due to Tyoe::dump() api difference + string conversions --- include/swift/AST/ExtInfo.h | 3 ++- lib/AST/ExtInfo.cpp | 5 +++-- lib/SILOptimizer/Transforms/StringOptimization.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 639b982d25e73..99a2d5ac176c0 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -30,6 +30,7 @@ namespace clang { class Type; +class ASTContext; } // namespace clang namespace swift { @@ -77,7 +78,7 @@ class ClangTypeInfo { /// Use the ClangModuleLoader to print the Clang type as a string. void printType(ClangModuleLoader *cml, llvm::raw_ostream &os) const; - void dump(llvm::raw_ostream &os) const; + void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const; }; // MARK: - FunctionTypeRepresentation diff --git a/lib/AST/ExtInfo.cpp b/lib/AST/ExtInfo.cpp index 26a8bb870a7bf..9b03d36d61d74 100644 --- a/lib/AST/ExtInfo.cpp +++ b/lib/AST/ExtInfo.cpp @@ -43,9 +43,10 @@ void ClangTypeInfo::printType(ClangModuleLoader *cml, cml->printClangType(type, os); } -void ClangTypeInfo::dump(llvm::raw_ostream &os) const { +void ClangTypeInfo::dump(llvm::raw_ostream &os, + const clang::ASTContext &ctx) const { if (type) { - type->dump(os); + type->dump(os, ctx); } else { os << ""; } diff --git a/lib/SILOptimizer/Transforms/StringOptimization.cpp b/lib/SILOptimizer/Transforms/StringOptimization.cpp index 5bb9b880f4c2d..1511456983311 100644 --- a/lib/SILOptimizer/Transforms/StringOptimization.cpp +++ b/lib/SILOptimizer/Transforms/StringOptimization.cpp @@ -235,7 +235,7 @@ bool StringOptimization::optimizeStringConcat(ApplyInst *concatCall) { // Replace lhs + rhs with "lhs + rhs" if both lhs and rhs are constant. if (lhsString.isConstant() && rhsString.isConstant()) { - std::string concat = lhsString.str; + std::string concat = lhsString.str.str(); concat += rhsString.str; if (ApplyInst *stringInit = createStringInit(concat, concatCall)) { concatCall->replaceAllUsesWith(stringInit); From bfef9d4b1263a3d9a62be1522e685ed43e678d28 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Tue, 4 Aug 2020 14:46:37 -0700 Subject: [PATCH 040/663] [Preset] Source compat suite cross compile for macOS arm64 --- utils/build-presets.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 9eaa76a841a99..bce0043209899 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2419,21 +2419,25 @@ swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;s mixin-preset=source_compat_suite_macos_base debug assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_macos_RA] mixin-preset=source_compat_suite_macos_base release assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_macos_R] mixin-preset=source_compat_suite_macos_base release no-assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_macos_D] mixin-preset=source_compat_suite_macos_base debug no-assertions +cross-compile-hosts=macosx-arm64 [preset: source_compat_suite_linux_DA] mixin-preset=source_compat_suite_linux_base From d913e57d84d7c20c652a3d8074811593c6960f99 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 6 Aug 2020 00:47:43 +0900 Subject: [PATCH 041/663] [Serialization] Serialize Differentiability WT index sorted When there are sil_property and sil_differentiability_witness at once, serialized file couldn't be deserialized because it's index table is serialized un-sortedly but deserializer assumes that contents of table index are sorted. This patch fixes the un-sorted serialization and adds test case to ensure that table index contents can be deserialized --- lib/Serialization/Serialization.cpp | 2 + lib/Serialization/SerializeSIL.cpp | 10 ++--- test/Serialization/index-table-order.sil | 51 ++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 test/Serialization/index-table-order.sil diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index c17453abfcf41..8c5cd273a7e3b 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -856,6 +856,8 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_NAMES); BLOCK_RECORD(sil_index_block, SIL_DEFAULT_WITNESS_TABLE_OFFSETS); BLOCK_RECORD(sil_index_block, SIL_PROPERTY_OFFSETS); + BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_NAMES); + BLOCK_RECORD(sil_index_block, SIL_DIFFERENTIABILITY_WITNESS_OFFSETS); #undef BLOCK #undef BLOCK_RECORD diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 849138d351534..3e318f2c2c068 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -2346,6 +2346,11 @@ void SILSerializer::writeIndexTables() { DefaultWitnessTableOffset); } + if (!PropertyOffset.empty()) { + Offset.emit(ScratchRecord, sil_index_block::SIL_PROPERTY_OFFSETS, + PropertyOffset); + } + if (!DifferentiabilityWitnessList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES, @@ -2355,11 +2360,6 @@ void SILSerializer::writeIndexTables() { DifferentiabilityWitnessOffset); } - if (!PropertyOffset.empty()) { - Offset.emit(ScratchRecord, sil_index_block::SIL_PROPERTY_OFFSETS, - PropertyOffset); - } - } void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { diff --git a/test/Serialization/index-table-order.sil b/test/Serialization/index-table-order.sil new file mode 100644 index 0000000000000..b31e59bba578a --- /dev/null +++ b/test/Serialization/index-table-order.sil @@ -0,0 +1,51 @@ +// RUN: %empty-directory(%t) + +// Ensure that serialized sib can be deserialized correctly assuming +// contents of SIL_INDEX_BLOCK are sorted by their ids +// RUN: %target-swift-frontend -emit-sib %s -module-name test -o %t/test.sib +// RUN: %target-swift-frontend -emit-sil %t/test.sib -module-name test +// CHECK-DAG: sil_vtable +// CHECK-DAG: sil_global +// CHECK-DAG: sil_witness_table +// CHECK-DAG: sil_default_witness_table +// CHECK-DAG: sil_property + +sil_stage canonical + +import Builtin +import Swift + +// For SIL_FUNC_NAMES +sil @id : $@convention(thin) (Float) -> Float { +bb0(%0 : $Float): + return %0 : $Float +} + + +// For SIL_VTABLE_NAMES +class C {} +sil_vtable C {} + +// For SIL_GLOBALVAR_NAMES +sil_global @x : $Int + +// For SIL_WITNESS_TABLE_NAMES +protocol P1 {} +struct S : P1 {} + +sil_witness_table S: P1 module test {} + +// For SIL_DEFAULT_WITNESS_TABLE_NAMES +protocol P2 {} +sil_default_witness_table P2 {} + +// For SIL_PROPERTY_OFFSETS +struct A { + var a: Int +} + +sil_property #A.a () + +// For SIL_DIFFERENTIABILITY_WITNESS_NAMES +sil_differentiability_witness [parameters 0] [results 0] @id : $@convention(thin) (Float) -> Float {} + From 9134e65fca8b67f24221280b47f31bd0183ed0e3 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Tue, 4 Aug 2020 15:46:58 -0400 Subject: [PATCH 042/663] Move Mutex test's threading helpers to a separate header so other tests can use them. --- unittests/runtime/Concurrent.cpp | 2 +- unittests/runtime/Mutex.cpp | 119 +----------------------- unittests/runtime/ThreadingHelpers.h | 134 +++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 118 deletions(-) create mode 100644 unittests/runtime/ThreadingHelpers.h diff --git a/unittests/runtime/Concurrent.cpp b/unittests/runtime/Concurrent.cpp index 3f78805c53ff7..d79a6a7498f74 100644 --- a/unittests/runtime/Concurrent.cpp +++ b/unittests/runtime/Concurrent.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information diff --git a/unittests/runtime/Mutex.cpp b/unittests/runtime/Mutex.cpp index 7d5dac159b923..eb634d5346449 100644 --- a/unittests/runtime/Mutex.cpp +++ b/unittests/runtime/Mutex.cpp @@ -16,125 +16,10 @@ #include #include #include -#include -using namespace swift; - -// When true many of the threaded tests log activity to help triage issues. -static bool trace = false; - -template -void threadedExecute(int threadCount, ThreadBody threadBody, - AfterSpinRelease afterSpinRelease) { - - std::vector threads; - - // Block the threads we are about to create. - std::atomic spinWait(true); - std::atomic readyCount(0); - std::atomic activeCount(0); - - for (int i = 0; i < threadCount; ++i) { - threads.push_back(std::thread([&, i] { - readyCount++; - - while (spinWait) { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - activeCount++; - - threadBody(i); - })); - } - - while (readyCount < threadCount) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - // Allow our threads to fight for the lock. - spinWait = false; - - while (activeCount < threadCount) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - afterSpinRelease(); - - // Wait until all of our threads have finished. - for (auto &thread : threads) { - thread.join(); - } -} - -template -void threadedExecute(int threadCount, ThreadBody threadBody) { - threadedExecute(threadCount, threadBody, [] {}); -} - -template -void threadedExecute(M &mutex, C &condition, bool &doneCondition, - ConsumerBody consumerBody, ProducerBody producerBody) { - - std::vector producers; - std::vector consumers; +#include "ThreadingHelpers.h" - // Block the threads we are about to create. - std::atomic spinWait(true); - - for (int i = 1; i <= 8; ++i) { - consumers.push_back(std::thread([&, i] { - while (spinWait) { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - consumerBody(i); - - if (trace) - printf("### Consumer[%d] thread exiting.\n", i); - })); - } - - for (int i = 1; i <= 5; ++i) { - producers.push_back(std::thread([&, i] { - while (spinWait) { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - producerBody(i); - - if (trace) - printf("### Producer[%d] thread exiting.\n", i); - })); - } - - // Poor mans attempt to get as many threads ready as possible before - // dropping spinWait, it doesn't have to be perfect. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - // Allow our threads to fight for the lock. - spinWait = false; - - // Wait until all of our producer threads have finished. - for (auto &thread : producers) { - thread.join(); - } - - // Inform consumers that producers are done. - mutex.withLockThenNotifyAll(condition, [&] { - if (trace) - printf("### Informing consumers we are done.\n"); - doneCondition = true; - }); - - // Wait for consumers to finish. - for (auto &thread : consumers) { - thread.join(); - } -} +using namespace swift; // ----------------------------------------------------------------------------- diff --git a/unittests/runtime/ThreadingHelpers.h b/unittests/runtime/ThreadingHelpers.h new file mode 100644 index 0000000000000..667c847959744 --- /dev/null +++ b/unittests/runtime/ThreadingHelpers.h @@ -0,0 +1,134 @@ +//===--- Concurrent.cpp - Concurrent data structure tests -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef THREADING_HELPERS_H +#define THREADING_HELPERS_H + +#include + +// When true many of the threaded tests log activity to help triage issues. +static bool trace = false; + +template +void threadedExecute(int threadCount, ThreadBody threadBody, + AfterSpinRelease afterSpinRelease) { + + std::vector threads; + + // Block the threads we are about to create. + std::atomic spinWait(true); + std::atomic readyCount(0); + std::atomic activeCount(0); + + for (int i = 0; i < threadCount; ++i) { + threads.push_back(std::thread([&, i] { + readyCount++; + + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + activeCount++; + + threadBody(i); + })); + } + + while (readyCount < threadCount) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + // Allow our threads to fight for the lock. + spinWait = false; + + while (activeCount < threadCount) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + afterSpinRelease(); + + // Wait until all of our threads have finished. + for (auto &thread : threads) { + thread.join(); + } +} + +template +void threadedExecute(int threadCount, ThreadBody threadBody) { + threadedExecute(threadCount, threadBody, [] {}); +} + +template +void threadedExecute(M &mutex, C &condition, bool &doneCondition, + ConsumerBody consumerBody, ProducerBody producerBody) { + + std::vector producers; + std::vector consumers; + + // Block the threads we are about to create. + std::atomic spinWait(true); + + for (int i = 1; i <= 8; ++i) { + consumers.push_back(std::thread([&, i] { + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + consumerBody(i); + + if (trace) + printf("### Consumer[%d] thread exiting.\n", i); + })); + } + + for (int i = 1; i <= 5; ++i) { + producers.push_back(std::thread([&, i] { + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + producerBody(i); + + if (trace) + printf("### Producer[%d] thread exiting.\n", i); + })); + } + + // Poor mans attempt to get as many threads ready as possible before + // dropping spinWait, it doesn't have to be perfect. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Allow our threads to fight for the lock. + spinWait = false; + + // Wait until all of our producer threads have finished. + for (auto &thread : producers) { + thread.join(); + } + + // Inform consumers that producers are done. + mutex.withLockThenNotifyAll(condition, [&] { + if (trace) + printf("### Informing consumers we are done.\n"); + doneCondition = true; + }); + + // Wait for consumers to finish. + for (auto &thread : consumers) { + thread.join(); + } +} + +#endif From 1ac565d6efa353bebb1e207855b092e23378c0a7 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Tue, 4 Aug 2020 15:48:09 -0400 Subject: [PATCH 043/663] Add a multithreaded test for ConcurrentReadableArray. --- unittests/runtime/Concurrent.cpp | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/unittests/runtime/Concurrent.cpp b/unittests/runtime/Concurrent.cpp index d79a6a7498f74..24a25a0d001f6 100644 --- a/unittests/runtime/Concurrent.cpp +++ b/unittests/runtime/Concurrent.cpp @@ -13,6 +13,8 @@ #include "swift/Runtime/Concurrent.h" #include "gtest/gtest.h" +#include "ThreadingHelpers.h" + using namespace swift; TEST(ConcurrentReadableArrayTest, SingleThreaded) { @@ -42,3 +44,48 @@ TEST(ConcurrentReadableArrayTest, SingleThreaded) { add(1000000); check(); } + +TEST(ConcurrentReadableArrayTest, MultiThreaded) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 100000; + + struct Value { + int threadNumber; + int x; + }; + ConcurrentReadableArray array; + + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + array.push_back({ threadNumber, i }); + }; + + auto reader = [&] { + int maxByThread[writerCount]; + bool done = false; + while (!done) { + for (int i = 0; i < writerCount; i++) + maxByThread[i] = -1; + for (auto element : array.snapshot()) { + ASSERT_LT(element.threadNumber, writerCount); + ASSERT_GT(element.x, maxByThread[element.threadNumber]); + maxByThread[element.threadNumber] = element.x; + } + done = true; + for (int i = 0; i < writerCount; i++) { + if (maxByThread[i] < insertCount - 1) + done = false; + } + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); + + ASSERT_EQ(array.snapshot().count(), writerCount * insertCount); +} From ecf8d556e55eeb51b3558fd9f3a5796b2cc47427 Mon Sep 17 00:00:00 2001 From: Ashley Garland Date: Fri, 7 Aug 2020 12:31:16 -0700 Subject: [PATCH 044/663] [SymbolGraph] Don't link type identifier fragments to private symbols These links will never resolve because the symbols are never emitted in the first place. rdar://64178490 --- lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp | 10 +++++++++- lib/SymbolGraphGen/DeclarationFragmentPrinter.h | 9 +++++++-- lib/SymbolGraphGen/SymbolGraph.cpp | 8 ++++---- .../DeclarationFragments/UnderscoreNotLinked.swift | 11 +++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 test/SymbolGraph/Symbols/Mixins/DeclarationFragments/UnderscoreNotLinked.swift diff --git a/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp b/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp index 4ef5f70b5ab4b..be82f22395e37 100644 --- a/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp +++ b/lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp @@ -138,7 +138,15 @@ void DeclarationFragmentPrinter::printTypeRef(Type T, const TypeDecl *RefTo, openFragment(FragmentKind::TypeIdentifier); printText(Name.str()); USR.clear(); - if (Name.str() != "Self") { + + auto ShouldLink = Name.str() != "Self"; + if (const auto *TD = T->getAnyNominal()) { + if (SG->isImplicitlyPrivate(TD)) { + ShouldLink = false; + } + } + + if (ShouldLink) { llvm::raw_svector_ostream OS(USR); ide::printDeclUSR(RefTo, OS); } diff --git a/lib/SymbolGraphGen/DeclarationFragmentPrinter.h b/lib/SymbolGraphGen/DeclarationFragmentPrinter.h index 580a37e2303ff..16e011669e062 100644 --- a/lib/SymbolGraphGen/DeclarationFragmentPrinter.h +++ b/lib/SymbolGraphGen/DeclarationFragmentPrinter.h @@ -59,6 +59,9 @@ class DeclarationFragmentPrinter : public ASTPrinter { Text, }; private: + /// The symbol graph for which a declaration is being printed. + const SymbolGraph *SG; + /// The output stream to print fragment objects to. llvm::json::OStream &OS; @@ -81,9 +84,11 @@ class DeclarationFragmentPrinter : public ASTPrinter { unsigned NumFragments; public: - DeclarationFragmentPrinter(llvm::json::OStream &OS, + DeclarationFragmentPrinter(const SymbolGraph *SG, + llvm::json::OStream &OS, Optional Key = None) - : OS(OS), + : SG(SG), + OS(OS), Kind(FragmentKind::None), NumFragments(0) { if (Key) { diff --git a/lib/SymbolGraphGen/SymbolGraph.cpp b/lib/SymbolGraphGen/SymbolGraph.cpp index 8ef75088237b8..cb2a2a1741504 100644 --- a/lib/SymbolGraphGen/SymbolGraph.cpp +++ b/lib/SymbolGraphGen/SymbolGraph.cpp @@ -558,7 +558,7 @@ void SymbolGraph::serializeDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); auto Options = getDeclarationFragmentsPrintOptions(); if (S.getSynthesizedBaseType()) { Options.setBaseType(S.getSynthesizedBaseType()); @@ -570,7 +570,7 @@ void SymbolGraph::serializeNavigatorDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); if (const auto *TD = dyn_cast(S.getSymbolDecl())) { Printer.printAbridgedType(TD, /*PrintKeyword=*/false); @@ -587,7 +587,7 @@ void SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); if (const auto *TD = dyn_cast(S.getSymbolDecl())) { Printer.printAbridgedType(TD, /*PrintKeyword=*/true); @@ -603,7 +603,7 @@ SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key, void SymbolGraph::serializeDeclarationFragments(StringRef Key, Type T, llvm::json::OStream &OS) { - DeclarationFragmentPrinter Printer(OS, Key); + DeclarationFragmentPrinter Printer(this, OS, Key); T->print(Printer, getDeclarationFragmentsPrintOptions()); } diff --git a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/UnderscoreNotLinked.swift b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/UnderscoreNotLinked.swift new file mode 100644 index 0000000000000..9fe3d6e819519 --- /dev/null +++ b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/UnderscoreNotLinked.swift @@ -0,0 +1,11 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name UnderscoreNotLinked -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name UnderscoreNotLinked -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/UnderscoreNotLinked.symbols.json + +public protocol _ShouldntBeLinked {} +public protocol ShouldBeLinked : _ShouldntBeLinked {} +public struct MyStruct : ShouldBeLinked {} + +// CHECK: "spelling": "_ShouldntBeLinked" +// CHECK-NOT: "preciseIdentifier": "s:19UnderscoreNotLinked011_ShouldntBeC0P" From 9bc787ef5f62ac0a310648e56674175dcbcaa194 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Thu, 23 Jul 2020 18:05:31 -0700 Subject: [PATCH 045/663] =?UTF-8?q?Add=20a=20=E2=80=9Ctypecheck=20module?= =?UTF-8?q?=20interface=E2=80=9D=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/swift/Frontend/FrontendOptions.h | 2 ++ include/swift/Frontend/ModuleInterfaceLoader.h | 14 +++++++++++++- include/swift/Option/FrontendOptions.td | 5 +++++ lib/Frontend/ArgsToFrontendOptionsConverter.cpp | 5 ++++- lib/Frontend/Frontend.cpp | 4 +++- lib/Frontend/FrontendOptions.cpp | 12 ++++++++++++ lib/Frontend/ModuleInterfaceBuilder.cpp | 5 +++++ lib/Frontend/ModuleInterfaceLoader.cpp | 7 +++++-- lib/FrontendTool/FrontendTool.cpp | 3 ++- test/ModuleInterface/unbuildable.swift | 13 +++++++++++-- 10 files changed, 62 insertions(+), 8 deletions(-) diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index aef89085fb34b..568ffd8f48821 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -116,6 +116,8 @@ class FrontendOptions { /// Build from a swiftinterface, as close to `import` as possible CompileModuleFromInterface, + /// Same as CompileModuleFromInterface, but stopping after typechecking + TypecheckModuleFromInterface, EmitSIBGen, ///< Emit serialized AST + raw SIL EmitSIB, ///< Emit serialized AST + canonical SIL diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 78116f109a8e8..df5eec399f6d7 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -263,6 +263,8 @@ class ExplicitModuleMapParser { }; struct ModuleInterfaceLoaderOptions { + FrontendOptions::ActionType requestedAction = + FrontendOptions::ActionType::EmitModuleOnly; bool remarkOnRebuildFromInterface = false; bool disableInterfaceLock = false; bool disableImplicitSwiftModule = false; @@ -271,7 +273,17 @@ struct ModuleInterfaceLoaderOptions { remarkOnRebuildFromInterface(Opts.RemarkOnRebuildFromModuleInterface), disableInterfaceLock(Opts.DisableInterfaceFileLock), disableImplicitSwiftModule(Opts.DisableImplicitModules), - mainExecutablePath(Opts.MainExecutablePath) {} + mainExecutablePath(Opts.MainExecutablePath) + { + switch (Opts.RequestedAction) { + case FrontendOptions::ActionType::TypecheckModuleFromInterface: + requestedAction = FrontendOptions::ActionType::Typecheck; + break; + default: + requestedAction = FrontendOptions::ActionType::EmitModuleOnly; + break; + } + } ModuleInterfaceLoaderOptions() = default; }; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 5bd693d2ffe7d..2007807b166d4 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -641,6 +641,11 @@ def build_module_from_parseable_interface : Alias, ModeOpt; +def typecheck_module_from_interface : + Flag<["-"], "typecheck-module-from-interface">, + HelpText<"Treat the (single) input as a swiftinterface and typecheck it">, + ModeOpt; + def module_interface_preserve_types_as_written : Flag<["-"], "module-interface-preserve-types-as-written">, HelpText<"When emitting a module interface, preserve types as they were " diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 05b0ed04f5083..541799fc8957e 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -147,7 +147,8 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.RequestedAction = determineRequestedAction(Args); } - if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface) { + if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface || + Opts.RequestedAction == FrontendOptions::ActionType::TypecheckModuleFromInterface) { // The situations where we use this action, e.g. explicit module building and // generating prebuilt module cache, don't need synchronization. We should avoid // using lock files for them. @@ -389,6 +390,8 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) { return FrontendOptions::ActionType::Immediate; if (Opt.matches(OPT_compile_module_from_interface)) return FrontendOptions::ActionType::CompileModuleFromInterface; + if (Opt.matches(OPT_typecheck_module_from_interface)) + return FrontendOptions::ActionType::TypecheckModuleFromInterface; llvm_unreachable("Unhandled mode option"); } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 7e000a0b6a563..7b2fa3ef30d4a 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -192,7 +192,9 @@ void CompilerInstance::recordPrimaryInputBuffer(unsigned BufID) { bool CompilerInstance::setUpASTContextIfNeeded() { if (Invocation.getFrontendOptions().RequestedAction == - FrontendOptions::ActionType::CompileModuleFromInterface) { + FrontendOptions::ActionType::CompileModuleFromInterface || + Invocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::TypecheckModuleFromInterface) { // Compiling a module interface from source uses its own CompilerInstance // with options read from the input file. Don't bother setting up an // ASTContext at this level. diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 1e1253ddcb6c5..eb11fdc6d19dd 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -51,6 +51,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::EmitModuleOnly: case ActionType::MergeModules: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: return true; case ActionType::Immediate: case ActionType::REPL: @@ -118,6 +119,7 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { case ActionType::Parse: case ActionType::ResolveImports: case ActionType::Typecheck: + case ActionType::TypecheckModuleFromInterface: case ActionType::DumpParse: case ActionType::DumpInterfaceHash: case ActionType::DumpAST: @@ -192,6 +194,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::DumpPCM: @@ -232,6 +235,7 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: @@ -280,6 +284,7 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: @@ -317,6 +322,7 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: @@ -360,6 +366,7 @@ bool FrontendOptions::canActionEmitModule(ActionType action) { case ActionType::DumpTypeInfo: case ActionType::EmitSILGen: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: @@ -404,6 +411,7 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) { case ActionType::EmitSILGen: case ActionType::EmitSIBGen: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: case ActionType::EmitPCM: @@ -450,6 +458,7 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) { case ActionType::EmitImportedModules: case ActionType::MergeModules: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::DumpTypeInfo: case ActionType::EmitPCM: case ActionType::DumpPCM: @@ -484,6 +493,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::Parse: case ActionType::ResolveImports: case ActionType::Typecheck: + case ActionType::TypecheckModuleFromInterface: case ActionType::DumpParse: case ActionType::DumpInterfaceHash: case ActionType::DumpAST: @@ -521,6 +531,7 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) { case ActionType::EmitImportedModules: case ActionType::EmitPCH: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: @@ -557,6 +568,7 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: case ActionType::Typecheck: case ActionType::ResolveImports: case ActionType::MergeModules: diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 4e118f04c0e5a..8a7e9b0268d0b 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -176,6 +176,8 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( return false; } FrontendOptions &FEOpts = subInvocation.getFrontendOptions(); + bool isTypeChecking = + (FEOpts.RequestedAction == FrontendOptions::ActionType::Typecheck); const auto &InputInfo = FEOpts.InputsAndOutputs.firstInput(); StringRef InPath = InputInfo.file(); const auto &OutputInfo = @@ -242,6 +244,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( if (ShouldSerializeDeps) SerializationOpts.Dependencies = Deps; SILMod->setSerializeSILAction([&]() { + if (isTypeChecking) + return; + // We don't want to serialize module docs in the cache -- they // will be serialized beside the interface file. serializeToBuffers(Mod, SerializationOpts, ModuleBuffer, diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index fed69f9a43f13..1cf23b5b4bc49 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1259,7 +1259,7 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( inheritOptionsForBuildingInterface(searchPathOpts, langOpts); // Configure front-end input. auto &SubFEOpts = genericSubInvocation.getFrontendOptions(); - SubFEOpts.RequestedAction = FrontendOptions::ActionType::EmitModuleOnly; + SubFEOpts.RequestedAction = LoaderOpts.requestedAction; if (!moduleCachePath.empty()) { genericSubInvocation.setClangModuleCachePath(moduleCachePath); } @@ -1442,7 +1442,10 @@ bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleN std::vector outputFiles{"/"}; std::vector ModuleOutputPaths; ModuleOutputPaths.emplace_back(); - ModuleOutputPaths.back().ModuleOutputPath = outputPath.str(); + if (subInvocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::EmitModuleOnly) { + ModuleOutputPaths.back().ModuleOutputPath = outputPath.str(); + } assert(subInvocation.getFrontendOptions().InputsAndOutputs.isWholeModule()); subInvocation.getFrontendOptions().InputsAndOutputs .setMainAndSupplementaryOutputs(outputFiles, ModuleOutputPaths); diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 37c2f1bf41190..07c921e8c0feb 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1711,7 +1711,8 @@ static bool performCompile(CompilerInstance &Instance, << Invocation.getLangOptions().Target.str() << '\n'; return false; } - if (Action == FrontendOptions::ActionType::CompileModuleFromInterface) + if (Action == FrontendOptions::ActionType::CompileModuleFromInterface || + Action == FrontendOptions::ActionType::TypecheckModuleFromInterface) return buildModuleFromInterface(Instance); if (Invocation.getInputKind() == InputFileKind::LLVM) diff --git a/test/ModuleInterface/unbuildable.swift b/test/ModuleInterface/unbuildable.swift index 42506ad70770f..48435c471de99 100644 --- a/test/ModuleInterface/unbuildable.swift +++ b/test/ModuleInterface/unbuildable.swift @@ -14,8 +14,15 @@ // // And finally, test: // -// RUN: not %target-swift-frontend -typecheck %s -I %t -DCURRENT 2>&1 | %FileCheck -check-prefix=CURRENT %s -// RUN: not %target-swift-frontend -typecheck %s -I %t -DFUTURE 2>&1 | %FileCheck -check-prefix=FUTURE %s +// RUN: not %target-swift-frontend -typecheck %s -I %t -DCURRENT 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT %s +// RUN: not %target-swift-frontend -typecheck %s -I %t -DFUTURE 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE %s +// +// Test that we get the same results when typechecking the interface: +// +// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableCurrent.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT-PREBUILD %s +// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableFuture.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE-PREBUILD %s + +// ALL: Unbuildable{{[^.]+}}.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#somethingYouveNeverHeardOf' #if CURRENT import UnbuildableCurrent @@ -25,3 +32,5 @@ import UnbuildableFuture // FUTURE: unbuildable.swift:[[@LINE-1]]:8: error: failed to build module 'UnbuildableFuture' from its module interface; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}' #endif +// CURRENT-PREBUILD: UnbuildableCurrent.swiftinterface:1:1: error: failed to build module 'UnbuildableCurrent' from its module interface; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced +// FUTURE-PREBUILD: UnbuildableFuture.swiftinterface:1:1: error: failed to build module 'UnbuildableFuture' from its module interface; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}' From d48e397b86cb771ea2bb7cbe398e08d8bf462bf0 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Fri, 24 Jul 2020 20:09:16 -0700 Subject: [PATCH 046/663] Support --driver-mode with swift-frontend This makes development in Xcode somewhat simpler. --- tools/driver/driver.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index ff189f773ab28..9ab571c111982 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -140,14 +140,15 @@ static int run_driver(StringRef ExecName, argv.data()+argv.size()), argv[0], (void *)(intptr_t)getExecutablePath); } - } - // Run the integrated Swift frontend when called as "swift-frontend" but - // without a leading "-frontend". - if (ExecName == "swift-frontend") { - return performFrontend(llvm::makeArrayRef(argv.data()+1, - argv.data()+argv.size()), - argv[0], (void *)(intptr_t)getExecutablePath); + // Run the integrated Swift frontend when called as "swift-frontend" but + // without a leading "-frontend". + if (!FirstArg.startswith("--driver-mode=") + && ExecName == "swift-frontend") { + return performFrontend(llvm::makeArrayRef(argv.data()+1, + argv.data()+argv.size()), + argv[0], (void *)(intptr_t)getExecutablePath); + } } std::string Path = getExecutablePath(argv[0]); From 3c698371029bb0619340aaf68f063f3c90b6dc0d Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Fri, 24 Jul 2020 20:44:13 -0700 Subject: [PATCH 047/663] Add a debug flag to emit invalid swiftinterface files --- include/swift/Frontend/ModuleInterfaceSupport.h | 5 ++++- include/swift/Option/FrontendOptions.td | 3 +++ lib/Frontend/CompilerInvocation.cpp | 2 ++ lib/Frontend/ModuleInterfaceSupport.cpp | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/swift/Frontend/ModuleInterfaceSupport.h b/include/swift/Frontend/ModuleInterfaceSupport.h index df576eb26d19a..f4c97c66c8f62 100644 --- a/include/swift/Frontend/ModuleInterfaceSupport.h +++ b/include/swift/Frontend/ModuleInterfaceSupport.h @@ -41,12 +41,15 @@ struct ModuleInterfaceOptions { /// back .swiftinterface and reconstructing .swiftmodule. std::string Flags; - // Print SPI decls and attributes. + /// Print SPI decls and attributes. bool PrintSPIs = false; /// Print imports with both @_implementationOnly and @_spi, only applies /// when PrintSPIs is true. bool ExperimentalSPIImports = false; + + /// Intentionally print invalid syntax into the file. + bool DebugPrintInvalidSyntax = false; }; extern version::Version InterfaceFormatVersion; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 2007807b166d4..86ed94acb9adf 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -256,6 +256,9 @@ def debug_forbid_typecheck_prefix : Separate<["-"], "debug-forbid-typecheck-pref HelpText<"Triggers llvm fatal_error if typechecker tries to typecheck a decl " "with the provided prefix name">; +def debug_emit_invalid_swiftinterface_syntax : Flag<["-"], "debug-emit-invalid-swiftinterface-syntax">, + HelpText<"Write an invalid declaration into swiftinterface files">; + def debug_cycles : Flag<["-"], "debug-cycles">, HelpText<"Print out debug dumps when cycles are detected in evaluation">; def build_request_dependency_graph : Flag<["-"], "build-request-dependency-graph">, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f9c3828c19c67..e43f2a99e1c64 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -325,6 +325,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts, Args.hasArg(OPT_experimental_print_full_convention); Opts.ExperimentalSPIImports |= Args.hasArg(OPT_experimental_spi_imports); + Opts.DebugPrintInvalidSyntax |= + Args.hasArg(OPT_debug_emit_invalid_swiftinterface_syntax); } /// Save a copy of any flags marked as ModuleInterfaceOption, if running diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index 65e094af7ccc8..21150755bdf2c 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -551,5 +551,8 @@ bool swift::emitSwiftInterface(raw_ostream &out, if (needDummyProtocolDeclaration) InheritedProtocolCollector::printDummyProtocolDeclaration(out); + if (Opts.DebugPrintInvalidSyntax) + out << "#__debug_emit_invalid_swiftinterface_syntax__\n"; + return false; } From 5f523fee669c84be3a0f2112b65a1271eff33dc6 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Fri, 7 Aug 2020 17:43:28 -0700 Subject: [PATCH 048/663] Add flag to verify just-emitted module interfaces The driver can now schedule jobs which typecheck just-emitted module interfaces to ensure that they can be consumed later. This can be enabled manually by passing `-verify-emitted-module-interface` to the driver. --- include/swift/Driver/Action.h | 23 +++++++++++- include/swift/Driver/ToolChain.h | 3 ++ include/swift/Option/Options.td | 9 +++++ lib/Driver/Action.cpp | 3 ++ lib/Driver/Driver.cpp | 20 +++++++++++ lib/Driver/ToolChain.cpp | 1 + lib/Driver/ToolChains.cpp | 35 +++++++++++++++++++ .../verify-module-interfaces.swift | 15 ++++++++ 8 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 test/ModuleInterface/verify-module-interfaces.swift diff --git a/include/swift/Driver/Action.h b/include/swift/Driver/Action.h index 02801d8aece66..df5bded05bb3b 100644 --- a/include/swift/Driver/Action.h +++ b/include/swift/Driver/Action.h @@ -51,9 +51,10 @@ class Action { GenerateDSYMJob, VerifyDebugInfoJob, GeneratePCHJob, + VerifyModuleInterfaceJob, JobFirst = CompileJob, - JobLast = GeneratePCHJob + JobLast = VerifyModuleInterfaceJob }; static const char *getClassName(Kind AC); @@ -357,6 +358,26 @@ class StaticLinkJobAction : public JobAction { } }; +class VerifyModuleInterfaceJobAction : public JobAction { + virtual void anchor(); + file_types::ID inputType; + +public: + VerifyModuleInterfaceJobAction(const Action * ModuleEmitter, + file_types::ID inputType) + : JobAction(Action::Kind::VerifyModuleInterfaceJob, { ModuleEmitter }, + file_types::TY_Nothing), inputType(inputType) { + assert(inputType == file_types::TY_SwiftModuleInterfaceFile || + inputType == file_types::TY_PrivateSwiftModuleInterfaceFile); + } + + file_types::ID getInputType() const { return inputType; } + + static bool classof(const Action *A) { + return A->getKind() == Action::Kind::VerifyModuleInterfaceJob; + } +}; + } // end namespace driver } // end namespace swift diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index cd55451a01c8b..7be6dffbe37cf 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -162,6 +162,9 @@ class ToolChain { virtual InvocationInfo constructInvocation(const VerifyDebugInfoJobAction &job, const JobContext &context) const; + virtual InvocationInfo + constructInvocation(const VerifyModuleInterfaceJobAction &job, + const JobContext &context) const; virtual InvocationInfo constructInvocation(const GeneratePCHJobAction &job, const JobContext &context) const; virtual InvocationInfo diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 01017c43315eb..b43eeef9f841d 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -460,6 +460,15 @@ def emit_private_module_interface_path : DoesNotAffectIncrementalBuild, ArgumentIsPath, SupplementaryOutput]>, MetaVarName<"">, HelpText<"Output private module interface file to ">; +def verify_emitted_module_interface : + Flag<["-"], "verify-emitted-module-interface">, + Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Check that module interfaces emitted during compilation typecheck">; +def no_verify_emitted_module_interface : + Flag<["-"], "no-verify-emitted-module-interface">, + Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Don't check that module interfaces emitted during compilation typecheck">; + def avoid_emit_module_source_info : Flag<["-"], "avoid-emit-module-source-info">, Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 0dcde774e73f8..25117800eed96 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -33,6 +33,7 @@ const char *Action::getClassName(Kind AC) { case Kind::GenerateDSYMJob: return "generate-dSYM"; case Kind::VerifyDebugInfoJob: return "verify-debug-info"; case Kind::GeneratePCHJob: return "generate-pch"; + case Kind::VerifyModuleInterfaceJob: return "verify-module-interface"; } llvm_unreachable("invalid class"); @@ -65,3 +66,5 @@ void GenerateDSYMJobAction::anchor() {} void VerifyDebugInfoJobAction::anchor() {} void GeneratePCHJobAction::anchor() {} + +void VerifyModuleInterfaceJobAction::anchor() {} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 4784a8ca9eaee..80b0c471c9d11 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2208,6 +2208,26 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, TopLevelActions.push_back(MergeModuleAction); TopLevelActions.append(AllLinkerInputs.begin(), AllLinkerInputs.end()); } + + bool verifyInterfacesByDefault = false; + + if (MergeModuleAction + && Args.hasFlag(options::OPT_verify_emitted_module_interface, + options::OPT_no_verify_emitted_module_interface, + verifyInterfacesByDefault)) { + if (Args.hasArgNoClaim(options::OPT_emit_module_interface, + options::OPT_emit_module_interface_path)) { + TopLevelActions.push_back( + C.createAction(MergeModuleAction, + file_types::TY_SwiftModuleInterfaceFile)); + } + + if (Args.hasArgNoClaim(options::OPT_emit_private_module_interface_path)) { + TopLevelActions.push_back( + C.createAction(MergeModuleAction, + file_types::TY_PrivateSwiftModuleInterfaceFile)); + } + } } bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) { diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 784348922f6fb..522a9727c454a 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -111,6 +111,7 @@ std::unique_ptr ToolChain::constructJob( CASE(GeneratePCHJob) CASE(AutolinkExtractJob) CASE(REPLJob) + CASE(VerifyModuleInterfaceJob) #undef CASE case Action::Kind::Input: llvm_unreachable("not a JobAction"); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index c6513efe2bf45..fef213d9e5eeb 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1047,6 +1047,41 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job, return II; } +ToolChain::InvocationInfo +ToolChain::constructInvocation(const VerifyModuleInterfaceJobAction &job, + const JobContext &context) const { + InvocationInfo II{SWIFT_EXECUTABLE_NAME}; + ArgStringList &Arguments = II.Arguments; + II.allowsResponseFiles = true; + + for (auto &s : getDriver().getSwiftProgramArgs()) + Arguments.push_back(s.c_str()); + Arguments.push_back("-frontend"); + + Arguments.push_back("-typecheck-module-from-interface"); + + size_t sizeBefore = Arguments.size(); + addInputsOfType(Arguments, context.Inputs, context.Args, job.getInputType()); + + (void)sizeBefore; + assert(Arguments.size() - sizeBefore == 1 && + "should verify exactly one module interface per job"); + + addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments); + addRuntimeLibraryFlags(context.OI, Arguments); + + addOutputsOfType(Arguments, context.Output, context.Args, + file_types::TY_SerializedDiagnostics, + "-serialize-diagnostics-path"); + + context.Args.AddLastArg(Arguments, options::OPT_import_objc_header); + + Arguments.push_back("-module-name"); + Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName)); + + return II; +} + ToolChain::InvocationInfo ToolChain::constructInvocation(const ModuleWrapJobAction &job, const JobContext &context) const { diff --git a/test/ModuleInterface/verify-module-interfaces.swift b/test/ModuleInterface/verify-module-interfaces.swift new file mode 100644 index 0000000000000..fcdd8677ff5aa --- /dev/null +++ b/test/ModuleInterface/verify-module-interfaces.swift @@ -0,0 +1,15 @@ +// RUN: %empty-directory(%t) + +// Check that verification won't reject a valid interface: +// RUN: %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -verify-emitted-module-interface -module-name MyModule %s + +// Check that verification will reject an invalid interface: +// RUN: not %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -verify-emitted-module-interface -module-name MyModule -Xfrontend -debug-emit-invalid-swiftinterface-syntax %s 2>&1 | %FileCheck %s + +// ...but not if verification is off. +// RUN: %target-build-swift -emit-library -enable-library-evolution -emit-module-interface -emit-module -swift-version 5 -o %t/MyModule.o -no-verify-emitted-module-interface -module-name MyModule -Xfrontend -debug-emit-invalid-swiftinterface-syntax %s + +public struct MyStruct {} + +// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#__debug_emit_invalid_swiftinterface_syntax__' +// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: failed to build module 'MyModule' from its module interface; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced From 22e3cff700dcdeab25a9deebdcd0845bf8a8b6f7 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Mon, 3 Aug 2020 01:18:55 -0700 Subject: [PATCH 049/663] Tweak diagnostic for failed module interface verification --- include/swift/AST/DiagnosticsSema.def | 12 ++++++------ lib/Frontend/ModuleInterfaceBuilder.cpp | 6 +++--- test/ModuleInterface/unbuildable.swift | 8 ++++---- test/ModuleInterface/verify-module-interfaces.swift | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 67d2f281c6ed0..1ded2e9765c6f 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -701,12 +701,12 @@ ERROR(sema_opening_import,Fatal, ERROR(serialization_load_failed,Fatal, "failed to load module '%0'", (StringRef)) ERROR(module_interface_build_failed,Fatal, - "failed to build module '%0' from its module interface; " - "%select{the compiler that produced it, '%2', may have used features " - "that aren't supported by this compiler, '%3'" - "|it may have been damaged or it may have triggered a bug in the Swift " - "compiler when it was produced}1", - (StringRef, bool, StringRef, StringRef)) + "failed to %select{build module '%1' from its module interface|verify " + "module interface of '%1'}0; %select{the compiler that produced it, " + "'%3', may have used features that aren't supported by this compiler, " + "'%4'|it may have been damaged or it may have triggered a bug in the " + "Swift compiler when it was produced}2", + (bool, StringRef, bool, StringRef, StringRef)) ERROR(serialization_malformed_module,Fatal, "malformed compiled module: %0", (StringRef)) ERROR(serialization_module_too_new,Fatal, diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 8a7e9b0268d0b..96d20c28d8ef5 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -200,9 +200,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( getSwiftInterfaceCompilerVersionForCurrentCompiler( SubInstance.getASTContext()); StringRef emittedByCompiler = info.CompilerVersion; - diagnose(diag::module_interface_build_failed, moduleName, - emittedByCompiler == builtByCompiler, emittedByCompiler, - builtByCompiler); + diagnose(diag::module_interface_build_failed, isTypeChecking, + moduleName, emittedByCompiler == builtByCompiler, + emittedByCompiler, builtByCompiler); } }; diff --git a/test/ModuleInterface/unbuildable.swift b/test/ModuleInterface/unbuildable.swift index 48435c471de99..3c1606164cfc7 100644 --- a/test/ModuleInterface/unbuildable.swift +++ b/test/ModuleInterface/unbuildable.swift @@ -19,8 +19,8 @@ // // Test that we get the same results when typechecking the interface: // -// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableCurrent.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT-PREBUILD %s -// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableFuture.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE-PREBUILD %s +// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableCurrent.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,CURRENT-VERIFY %s +// RUN: not %target-swift-frontend -typecheck-module-from-interface %t/UnbuildableFuture.swiftinterface 2>&1 | %FileCheck -check-prefixes=ALL,FUTURE-VERIFY %s // ALL: Unbuildable{{[^.]+}}.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#somethingYouveNeverHeardOf' @@ -32,5 +32,5 @@ import UnbuildableFuture // FUTURE: unbuildable.swift:[[@LINE-1]]:8: error: failed to build module 'UnbuildableFuture' from its module interface; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}' #endif -// CURRENT-PREBUILD: UnbuildableCurrent.swiftinterface:1:1: error: failed to build module 'UnbuildableCurrent' from its module interface; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced -// FUTURE-PREBUILD: UnbuildableFuture.swiftinterface:1:1: error: failed to build module 'UnbuildableFuture' from its module interface; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}' +// CURRENT-VERIFY: UnbuildableCurrent.swiftinterface:1:1: error: failed to verify module interface of 'UnbuildableCurrent'; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced +// FUTURE-VERIFY: UnbuildableFuture.swiftinterface:1:1: error: failed to verify module interface of 'UnbuildableFuture'; the compiler that produced it, 'NeoTokyoSwift 2000.42', may have used features that aren't supported by this compiler, '{{.*Swift version.*}}' diff --git a/test/ModuleInterface/verify-module-interfaces.swift b/test/ModuleInterface/verify-module-interfaces.swift index fcdd8677ff5aa..191360f2bfb90 100644 --- a/test/ModuleInterface/verify-module-interfaces.swift +++ b/test/ModuleInterface/verify-module-interfaces.swift @@ -12,4 +12,4 @@ public struct MyStruct {} // CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: use of unknown directive '#__debug_emit_invalid_swiftinterface_syntax__' -// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: failed to build module 'MyModule' from its module interface; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced +// CHECK: MyModule.swiftinterface:{{[0-9]+}}:{{[0-9]+}}: error: failed to verify module interface of 'MyModule'; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced From f82420491cd84ef66193bc701928ef0610f18904 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Fri, 7 Aug 2020 17:44:16 -0700 Subject: [PATCH 050/663] Verify interfaces by default in assert compilers Isolated into its own commit so that it can be reverted easily. --- lib/Driver/Driver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 80b0c471c9d11..8d94f5ff9b7ac 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2209,7 +2209,11 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, TopLevelActions.append(AllLinkerInputs.begin(), AllLinkerInputs.end()); } +#ifdef NDEBUG bool verifyInterfacesByDefault = false; +#else + bool verifyInterfacesByDefault = true; +#endif if (MergeModuleAction && Args.hasFlag(options::OPT_verify_emitted_module_interface, From 6773d7e0c5b2487d6534107b01c08ee57f546e20 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 6 Aug 2020 15:40:54 -0700 Subject: [PATCH 051/663] [NFC] [ModuleTrace] Add negative test for cycles in trace emission. Context: rdar://66512316. --- .../ComplexModuleGraph2/CoreDaemon.h | 5 + .../ComplexModuleGraph2/CoreMemory.h | 4 + .../ComplexModuleGraph2/DaemonKit.h | 5 + .../ComplexModuleGraph2/FilesystemKit.h | 5 + .../ComplexModuleGraph2/MemoryKit.h | 7 + .../ComplexModuleGraph2/module.modulemap | 29 +++ .../loaded_module_trace_directness_2.swift | 189 ++++++++++++++++++ 7 files changed, 244 insertions(+) create mode 100644 test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreDaemon.h create mode 100644 test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreMemory.h create mode 100644 test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit.h create mode 100644 test/Driver/Inputs/imported_modules/ComplexModuleGraph2/FilesystemKit.h create mode 100644 test/Driver/Inputs/imported_modules/ComplexModuleGraph2/MemoryKit.h create mode 100644 test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap create mode 100644 test/Driver/loaded_module_trace_directness_2.swift diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreDaemon.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreDaemon.h new file mode 100644 index 0000000000000..82d8f39a18d69 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreDaemon.h @@ -0,0 +1,5 @@ +typedef void Runner(int); + +struct Daemon { + Runner *run; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreMemory.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreMemory.h new file mode 100644 index 0000000000000..058328d0f82a9 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/CoreMemory.h @@ -0,0 +1,4 @@ +struct MemoryMapRegion { + void *start; + void *end; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit.h new file mode 100644 index 0000000000000..bb28f0606b6a3 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit.h @@ -0,0 +1,5 @@ +#import + +struct DaemonPair { + struct Daemon daemons[2]; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/FilesystemKit.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/FilesystemKit.h new file mode 100644 index 0000000000000..5956aaf20c0cf --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/FilesystemKit.h @@ -0,0 +1,5 @@ +#import + +struct FileStorage { + MyNode *nodes[4]; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/MemoryKit.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/MemoryKit.h new file mode 100644 index 0000000000000..fd8b265646ccc --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/MemoryKit.h @@ -0,0 +1,7 @@ +#import +#import + +struct MemoryMap { + MemoryMapEntry *entries; + unsigned count; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap new file mode 100644 index 0000000000000..d0673487e9836 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap @@ -0,0 +1,29 @@ +module CoreFilesystem { + header "CoreFilesystem-Generated.h" + export * +} + +module FilesystemKit { + header "FilesystemKit.h" + export * +} + +module CoreDaemon { + header "CoreDaemon.h" + export * +} + +module DaemonKit { + header "DaemonKit.h" + export * +} + +module CoreMemory { + header "CoreMemory.h" + export * +} + +module MemoryKit { + header "MemoryKit.h" + export * +} diff --git a/test/Driver/loaded_module_trace_directness_2.swift b/test/Driver/loaded_module_trace_directness_2.swift new file mode 100644 index 0000000000000..62a3314e0e7ed --- /dev/null +++ b/test/Driver/loaded_module_trace_directness_2.swift @@ -0,0 +1,189 @@ +// RUN: %empty-directory(%t) +// RUN: cp -r %S/Inputs/imported_modules/ComplexModuleGraph2 %t/include + +// REQUIRES: objc_interop + +// Dependency graph: +// +// * CoreFilesystem - Swift module with generated ObjC header +// * FilesystemKit - ObjC module without overlay, has #import +// * TestFilesystem - Swift module, has import CoreFilesystem or FilesystemKit. +// +// * CoreDaemon - ObjC module with overlay, the overlay has import DaemonKit +// * DaemonKit - ObjC module without overlay, has #import +// * TestDaemon - Swift module, has import CoreDaemon or DaemonKit. +// NOTE: This mimics the Darwin -> SwiftOverlayShims -> Darwin dependency "cycle". +// +// * CoreMemory - ObjC module with overlay and generated header for overlay, the overlay has import MemoryKit +// * MemoryKit - ObjC module without overlay, has #import +// * TestMemory - Swift module, has import CoreMemory or MemoryKit. + +// 1. CoreFilesystem - Build. + +// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreFilesystem.swiftmodule -DCoreFilesystem -module-name CoreFilesystem -emit-objc-header-path %t/include/CoreFilesystem-Generated.h -disable-objc-attr-requires-foundation-module + +#if CoreFilesystem +@objc +public class MyNode { + public var number: Int + public init(_ n: Int) { number = n } +} +#endif + +// 2. FilesystemKit - Nothing to do (pure Clang module). + +// 3. TestFilesystem - Check that CoreFilesystem and Filesytem can be imported. + +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV1 -module-name TestFilesystemV1 -emit-loaded-module-trace-path %t/TestFilesystemV1.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV1.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV2 -module-name TestFilesystemV2 -emit-loaded-module-trace-path %t/TestFilesystemV2.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV2.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV3 -module-name TestFilesystemV3 -emit-loaded-module-trace-path %t/TestFilesystemV3.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV3.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestFilesystem -DV4 -module-name TestFilesystemV4 -emit-loaded-module-trace-path %t/TestFilesystemV4.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTFILESYSTEM < %t/TestFilesystemV4.trace.json + +#if TestFilesystem + #if V1 + import CoreFilesystem + #endif + #if V2 + import FilesystemKit + public func noop(_: CoreFilesystem.MyNode) {} + #endif + #if V3 + import CoreFilesystem + import FilesystemKit + #endif + #if V4 + import FilesystemKit + import CoreFilesystem + #endif +#endif + +// FilesystemKit has no overlay, so it shouldn't show up. +// TESTFILESYSTEM: "swiftmodulesDetailedInfo":[ +// TESTFILESYSTEM-NOT: FilesystemKit +// TESTFILESYSTEM-DAG: {"name":"CoreFilesystem","path":"{{[^"]*}}CoreFilesystem.swiftmodule","isImportedDirectly":true, +// TESTFILESYSTEM: ] + +// 4. CoreDaemon - Build. + +// FIXME: Trace emission shouldn't crash. +// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreDaemon.swiftmodule -DCoreDaemon -module-name CoreDaemon -I %t/include +// RUN: not --crash %target-swift-frontend %s -typecheck -DCoreDaemon -module-name CoreDaemon -emit-loaded-module-trace-path %t/CoreDaemon.trace.json -I %t/include 2>/dev/null +// SKIP: %FileCheck %s --check-prefix=COREDAEMON < %t/CoreDaemon.trace.json + +// * CoreDaemon - ObjC module with overlay, the overlay has import DaemonKit +// * DaemonKit - ObjC module without overlay, has #import +// * TestDaemon - Swift module, has import CoreDaemon or DaemonKit. + +#if CoreDaemon +@_exported import CoreDaemon +import DaemonKit + +public func runBoth(_ pair: DaemonKit.DaemonPair) { + let daemons : (CoreDaemon.Daemon, CoreDaemon.Daemon) = pair.daemons; + daemons.0.run(0); + daemons.1.run(1); +} +#endif + +// COREDAEMON: "swiftmodulesDetailedInfo":[ +// COREDAEMON-NOT: CoreDaemon +// COREDAEMON-NOT: DaemonKit +// COREDAEMON: ] + +// 5. DaemonKit - Nothing to do (pure Clang module). + +// 6. TestCoreDaemon + +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV1 -module-name TestDaemonV1 -emit-loaded-module-trace-path %t/TestDaemonV1.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV1.trace.json + +// FIXME: Trace emission shouldn't crash. +// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include 2>/dev/null +// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json + +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV3 -module-name TestDaemonV3 -emit-loaded-module-trace-path %t/TestDaemonV3.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV3.trace.json + +// FIXME: Trace emission shouldn't crash. +// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include 2>/dev/null +// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json + +#if TestDaemon + #if V1 + import CoreDaemon + #endif + #if V2 + import DaemonKit + public func noop(_: CoreDaemon.Daemon) {} + #endif + #if V3 + import CoreDaemon + import DaemonKit + #endif + #if V4 + import DaemonKit + import CoreDaemon + #endif +#endif + +// DaemonKit has no overlay, so it shouldn't show up. +// TESTDAEMON: "swiftmodulesDetailedInfo":[ +// TESTDAEMON-NOT: DaemonKit +// TESTDAEMON-DAG: {"name":"CoreDaemon","path":"{{[^"]*}}CoreDaemon.swiftmodule","isImportedDirectly":true, +// TESTDAEMON: ] + +// 7. CoreMemory - Build. + +// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreMemory.swiftmodule -DCoreMemory -module-name CoreMemory -emit-objc-header-path %t/include/CoreMemory-Generated.h -disable-objc-attr-requires-foundation-module -I %t/include + +#if CoreMemory +@_exported import CoreMemory + +@objc +public class MemoryMapEntry { + public var region: MemoryMapRegion + public var permissions: Int = 0 + public init(_ r: MemoryMapRegion) { region = r } +} +#endif + +// 8. MemoryKit - Nothing to do (pure Clang module). + +// 9. TestMemory - Check that CoreMemory and MemoryKit can be imported. + +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV1 -module-name TestMemoryV1 -emit-loaded-module-trace-path %t/TestMemoryV1.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV1.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV2 -module-name TestMemoryV2 -emit-loaded-module-trace-path %t/TestMemoryV2.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV2.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV3 -module-name TestMemoryV3 -emit-loaded-module-trace-path %t/TestMemoryV3.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV3.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestMemory -DV4 -module-name TestMemoryV4 -emit-loaded-module-trace-path %t/TestMemoryV4.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTMEMORY < %t/TestMemoryV4.trace.json + +#if TestMemory + #if V1 + import CoreMemory + #endif + #if V2 + import MemoryKit + public func noop(_: CoreMemory.MemoryMapRegion, _: CoreMemory.MemoryMapEntry) {} + #endif + #if V3 + import CoreMemory + import MemoryKit + #endif + #if V4 + import MemoryKit + import CoreMemory + #endif +#endif + +// MemoryKit has no overlay, so it shouldn't show up. +// TESTMEMORY: "swiftmodulesDetailedInfo":[ +// TESTMEMORY-NOT: MemoryKit +// TESTMEMORY-DAG: {"name":"CoreMemory","path":"{{[^"]*}}CoreMemory.swiftmodule","isImportedDirectly":true, +// TESTMEMORY: ] From 99cefe707e31a73f0f6298e1ab52412122db57ec Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Fri, 7 Aug 2020 16:38:26 -0700 Subject: [PATCH 052/663] [ModuleTrace] Handle cycle detection edge case in module trace emission. Fixes rdar://66512316. --- lib/FrontendTool/FrontendTool.cpp | 77 ++++++++++++++++++- .../loaded_module_trace_directness_2.swift | 16 ++-- 2 files changed, 79 insertions(+), 14 deletions(-) diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7d581d7b3366d..7cd611d221557 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -328,6 +328,9 @@ class ABIDependencyEvaluator { llvm::DenseSet visited; + /// Cache to avoid recomputing public imports of Swift modules repeatedly. + llvm::DenseMap isOverlayCache; + /// Helper function to handle invariant violations as crashes in debug mode. void crashOnInvariantViolation( llvm::function_ref f) const; @@ -342,6 +345,31 @@ class ABIDependencyEvaluator { void reexposeImportedABI(ModuleDecl *module, ModuleDecl *importedModule, bool includeImportedModule = true); + /// Check if a Swift module is an overlay for some Clang module. + /// + /// FIXME: Delete this hack once SR-13363 is fixed and ModuleDecl has the + /// right API which we can use directly. + bool isOverlayOfClangModule(ModuleDecl *swiftModule); + + /// Check for cases where we have a fake cycle through an overlay. + /// + /// \code + /// Actual stack: + /// sandwichedModule -> Overlay (Swift) -> ... -> sandwichedModule + /// ^^--- wrong! + /// Ideal stack: + /// sandwichedModule -> Underlying (Clang) + /// \endcode + /// + /// This happens when we have a dependency like: + /// \code + /// Overlay (Swift) -> sandwichedModule -> Underlying (Clang) + /// \endcode + /// + /// We check this lazily because eagerly detecting if the dependency on an + /// overlay is correct or not is difficult. + bool isFakeCycleThroughOverlay(ModuleDecl **sandwichedModuleIter); + /// Recursive step in computing ABI dependencies. /// /// Use this method instead of using the \c forClangModule/\c forSwiftModule @@ -453,9 +481,47 @@ void ABIDependencyEvaluator::reexposeImportedABI( addToABIExportMap(module, reexportedModule); } +bool ABIDependencyEvaluator::isOverlayOfClangModule(ModuleDecl *swiftModule) { + assert(!swiftModule->isNonSwiftModule()); + + auto cacheEntry = isOverlayCache.find(swiftModule); + if (cacheEntry != isOverlayCache.end()) + return cacheEntry->second; + + llvm::SmallPtrSet importList; + ::getImmediateImports(swiftModule, importList, + {ModuleDecl::ImportFilterKind::Public}); + bool isOverlay = + llvm::any_of(importList, [&](ModuleDecl *importedModule) -> bool { + return isClangOverlayOf(swiftModule, importedModule); + }); + isOverlayCache[swiftModule] = isOverlay; + return isOverlay; +} + +bool ABIDependencyEvaluator::isFakeCycleThroughOverlay( + ModuleDecl **sandwichModuleIter) { + assert(sandwichModuleIter >= searchStack.begin() + && sandwichModuleIter < searchStack.end() + && "sandwichModuleIter points to an element in searchStack"); + // The sandwichedModule must be a Clang module. + if (!(*sandwichModuleIter)->isNonSwiftModule()) + return false; + auto nextModuleIter = sandwichModuleIter + 1; + if (nextModuleIter == searchStack.end()) + return false; + // The next module must be a Swift overlay for a Clang module + if ((*nextModuleIter)->isNonSwiftModule()) + return false; + return isOverlayOfClangModule(*nextModuleIter); +} + void ABIDependencyEvaluator::computeABIDependenciesForModule( ModuleDecl *module) { - if (llvm::find(searchStack, module) != searchStack.end()) { + auto moduleIter = llvm::find(searchStack, module); + if (moduleIter != searchStack.end()) { + if (isFakeCycleThroughOverlay(moduleIter)) + return; crashOnInvariantViolation([&](llvm::raw_string_ostream &os) { os << "unexpected cycle in import graph!\n"; for (auto m: searchStack) { @@ -510,6 +576,10 @@ void ABIDependencyEvaluator::computeABIDependenciesForClangModule( // C' imports S. This creates a cycle: S -> C' -> ... -> S. // In practice, this case is hit for // Darwin (Swift) -> SwiftOverlayShims (Clang) -> Darwin (Swift). + // We may also hit this in a slightly different direction, in case + // the module directly imports SwiftOverlayShims: + // SwiftOverlayShims -> Darwin (Swift) -> SwiftOverlayShims + // The latter is handled later by isFakeCycleThroughOverlay. // 3. [NOTE: Intra-module-leafwards-traversal] // Cycles within the same top-level module. // These don't matter for us, since we only care about the dependency @@ -519,9 +589,8 @@ void ABIDependencyEvaluator::computeABIDependenciesForClangModule( if (import->isStdlibModule()) { continue; } - if (!import->isNonSwiftModule() - && import->findUnderlyingClangModule() != nullptr - && llvm::find(searchStack, import) != searchStack.end()) { + if (!import->isNonSwiftModule() && isOverlayOfClangModule(import) && + llvm::find(searchStack, import) != searchStack.end()) { continue; } if (import->isNonSwiftModule() diff --git a/test/Driver/loaded_module_trace_directness_2.swift b/test/Driver/loaded_module_trace_directness_2.swift index 62a3314e0e7ed..95f06446c1df1 100644 --- a/test/Driver/loaded_module_trace_directness_2.swift +++ b/test/Driver/loaded_module_trace_directness_2.swift @@ -69,10 +69,8 @@ public class MyNode { // 4. CoreDaemon - Build. -// FIXME: Trace emission shouldn't crash. -// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreDaemon.swiftmodule -DCoreDaemon -module-name CoreDaemon -I %t/include -// RUN: not --crash %target-swift-frontend %s -typecheck -DCoreDaemon -module-name CoreDaemon -emit-loaded-module-trace-path %t/CoreDaemon.trace.json -I %t/include 2>/dev/null -// SKIP: %FileCheck %s --check-prefix=COREDAEMON < %t/CoreDaemon.trace.json +// RUN: %target-swift-frontend %s -emit-module -o %t/include/CoreDaemon.swiftmodule -DCoreDaemon -module-name CoreDaemon -emit-loaded-module-trace-path %t/CoreDaemon.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=COREDAEMON < %t/CoreDaemon.trace.json // * CoreDaemon - ObjC module with overlay, the overlay has import DaemonKit // * DaemonKit - ObjC module without overlay, has #import @@ -101,16 +99,14 @@ public func runBoth(_ pair: DaemonKit.DaemonPair) { // RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV1 -module-name TestDaemonV1 -emit-loaded-module-trace-path %t/TestDaemonV1.trace.json -I %t/include // RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV1.trace.json -// FIXME: Trace emission shouldn't crash. -// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include 2>/dev/null -// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json // RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV3 -module-name TestDaemonV3 -emit-loaded-module-trace-path %t/TestDaemonV3.trace.json -I %t/include // RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV3.trace.json -// FIXME: Trace emission shouldn't crash. -// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include 2>/dev/null -// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json #if TestDaemon #if V1 From 962106fed3bb10bc47bb032fd67114620db29030 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 6 Aug 2020 13:55:28 -0700 Subject: [PATCH 053/663] [semantic-arc] When computing Lifetimes include all consuming uses, not just the final destroying use. TLDR: This fixes an ownership verifier assert caused by not placing end_borrows along paths where an enum is provable to have a trivial case. It only happens if all non-trivial cases in a switch_enum are "dead end blocks" where the program will end and we leak objects. The Problem ----------- The actual bug here only occurs in cases where we have a switch_enum on an enum with mixed trivial, non-trivial cases and all of the non-trivial payloaded cases are "dead end blocks". As an example, lets look at a simple switch_enum over an optional where the .some case is a dead end block and we leak the Klass object into program termination: ``` %0 = load [copy] %mem : $Klass switch_enum %0 : $Optional, case #Optional.some: bbDeadEnd, case #Optional.none: bbContinue bbDeadEnd(%0a : @owned $Klass): // %0 is leaked into program end! unreachable bbContinue: ... // program continue. ``` In this case, if we were only looking at final destroying uses, we would pass a def without any uses to the ValueLifetimeChecker causing us to not have a frontier at all causing us to not insert any end_borrows, yielding: ``` %0 = load_borrow %mem : $Klass switch_enum %0 : $Optional, case #Optional.some: bbDeadEnd, case #Optional.none: bbContinue bbDeadEnd(%0a : @guaranteed $Klass): // %0 is leaked into program end and // doesnt need an end_borrow! unreachable bbContinue: ... // program continue... we need an end_borrow here though! ``` This then trips the ownership verifier since switch_enum is a transforming terminator that acts like a forwarding instruction implying we need an end_borrow on the base value along all non-dead end paths through the program. Importantly this is not actually a leak of a value or unsafe behavior since the only time that we enter into unsafe territory is along paths where the enum was actually trivial. So the load_borrow is actually just loaded the trivial enum value. The Fix ------- In order to work around this, I realized that the right solution is to also include the forwarding consuming uses (in this case the switch_enum use) when determining the lifetime and that this solves the problem. That being said, after I made that change, I noticed that I needed to remove my previous manner of computing the insertion point to use for arguments when finding the lifetime using ValueLifetimeAnalysis. Previously since I was using only the destroying uses I knew that the destroy_value could not be the first instruction in the block of my argument since I handled that case individually before using the ValueLifetimeAnalysis. That invariant is no longer true as can be seen in the case above if %0 was from a SILArgument itself instead of a load [copy] and we were converting that argument to be a guaranteed argument. To fix this, I taught ValueLifetimeAnalysis how to handle defs from Arguments. The key thing is I noticed while reading the code that the analysis only generally cared about the instruction's parent block. Beyond that, the def being from an instruction was only needed to determine if a user is earlier in the same block as the def instruction. Those concerns not apply to SILArgument which dominate all instructions in the same block, so in this patch, we just skip those conditional checks when we have a SILArgument. The rest of the code that uses the parent block is the same for both SILArgument/SILInstructions. rdar://65244617 --- .../swift/SILOptimizer/Utils/ValueLifetime.h | 53 ++++++----- .../Transforms/SemanticARCOpts.cpp | 46 ++++------ lib/SILOptimizer/Utils/ValueLifetime.cpp | 89 +++++++++++++------ test/SILOptimizer/semantic-arc-opts.sil | 73 ++++++++++++++- 4 files changed, 184 insertions(+), 77 deletions(-) diff --git a/include/swift/SILOptimizer/Utils/ValueLifetime.h b/include/swift/SILOptimizer/Utils/ValueLifetime.h index d4e5bb5b1ba53..92af2083ef62f 100644 --- a/include/swift/SILOptimizer/Utils/ValueLifetime.h +++ b/include/swift/SILOptimizer/Utils/ValueLifetime.h @@ -28,6 +28,24 @@ namespace swift { /// of the analysis and can be a super set of the uses of the SILValue /// e.g. it can be the set of transitive uses of the SILValue. class ValueLifetimeAnalysis { + /// The instruction or argument that define the value. + PointerUnion defValue; + + /// The set of blocks where the value is live. + llvm::SmallSetVector liveBlocks; + + /// The set of instructions where the value is used, or the users-list + /// provided with the constructor. + llvm::SmallPtrSet userSet; + + /// Indicates whether the basic block containing def has users of def that + /// precede def. This field is initialized by propagateLiveness. + bool hasUsersBeforeDef; + + /// Critical edges that couldn't be split to compute the frontier. This could + /// be non-empty when the analysis is invoked with DontModifyCFG mode. + llvm::SmallVector, 16> criticalEdges; + public: /// The lifetime frontier for the value. It is the list of instructions @@ -35,13 +53,13 @@ class ValueLifetimeAnalysis { /// end the value's lifetime. using Frontier = SmallVector; - /// Constructor for the value \p Def with a specific range of users. + /// Constructor for the value \p def with a specific range of users. /// /// We templatize over the RangeTy so that we can initialize /// ValueLifetimeAnalysis with misc iterators including transform /// iterators. template - ValueLifetimeAnalysis(SILInstruction *def, const RangeTy &userRange) + ValueLifetimeAnalysis(decltype(defValue) def, const RangeTy &userRange) : defValue(def), userSet(userRange.begin(), userRange.end()) { propagateLiveness(); } @@ -102,7 +120,7 @@ class ValueLifetimeAnalysis { /// Returns true if the value is alive at the begin of block \p bb. bool isAliveAtBeginOfBlock(SILBasicBlock *bb) { return liveBlocks.count(bb) && - (bb != defValue->getParent() || hasUsersBeforeDef); + (hasUsersBeforeDef || bb != getDefValueParentBlock()); } /// Checks if there is a dealloc_ref inside the value's live range. @@ -112,24 +130,19 @@ class ValueLifetimeAnalysis { void dump() const; private: + SILFunction *getFunction() const { + if (auto *inst = defValue.dyn_cast()) { + return inst->getFunction(); + } + return defValue.get()->getFunction(); + } - /// The value. - SILInstruction *defValue; - - /// The set of blocks where the value is live. - llvm::SmallSetVector liveBlocks; - - /// The set of instructions where the value is used, or the users-list - /// provided with the constructor. - llvm::SmallPtrSet userSet; - - /// Indicates whether the basic block containing def has users of def that - /// precede def. This field is initialized by propagateLiveness. - bool hasUsersBeforeDef; - - /// Critical edges that couldn't be split to compute the frontier. This could - /// be non-empty when the analysis is invoked with DontModifyCFG mode. - llvm::SmallVector, 16> criticalEdges; + SILBasicBlock *getDefValueParentBlock() const { + if (auto *inst = defValue.dyn_cast()) { + return inst->getParent(); + } + return defValue.get()->getParent(); + } /// Propagates the liveness information up the control flow graph. void propagateLiveness(); diff --git a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp index 45a05e6c0db3c..743dac16eaa6b 100644 --- a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp @@ -245,6 +245,10 @@ class OwnershipLiveRange { TransformRange, OperandToUser>; DestroyingInstsRange getDestroyingInsts() const; + using ConsumingInstsRange = + TransformRange, OperandToUser>; + ConsumingInstsRange getAllConsumingInsts() const; + /// If this LiveRange has a single destroying use, return that use. Otherwise, /// return nullptr. Operand *getSingleDestroyingUse() const { @@ -335,6 +339,11 @@ OwnershipLiveRange::getDestroyingInsts() const { return DestroyingInstsRange(getDestroyingUses(), OperandToUser()); } +OwnershipLiveRange::ConsumingInstsRange +OwnershipLiveRange::getAllConsumingInsts() const { + return ConsumingInstsRange(consumingUses, OperandToUser()); +} + OwnershipLiveRange::OwnershipLiveRange(SILValue value) : introducer(*OwnedValueIntroducer::get(value)), destroyingUses(), ownershipForwardingUses(), unknownConsumingUses() { @@ -464,36 +473,17 @@ void OwnershipLiveRange::insertEndBorrowsAtDestroys( // // TODO: Hoist this out? SILInstruction *inst = introducer.value->getDefiningInstruction(); + Optional analysis; if (!inst) { - // If our introducer was not for an inst, it should be from an arg. In such - // a case, we handle one of two cases: - // - // 1. If we have one destroy and that destroy is the initial instruction in - // the arguments block, we just insert the end_borrow here before the - // destroy_value and bail. If the destroy is not the initial instruction in - // the arg block, we delegate to the ValueLifetimeAnalysis code. - // - // 2. If we have multiple destroys, by the properties of owned values having - // a linear lifetime, we know that the destroys can not both be first in the - // args block since the only way that we could have two such destroys in the - // arg's block is if we destructured the arg. In such a case, the - // destructure instruction would have to be between the argument and any - // destroy meaning the destroys could not be first. In such a case, we - // delegate to the ValueLifetimeAnalysis code. - auto *arg = cast(introducer.value); - auto *beginInst = &*arg->getParent()->begin(); - if (auto *singleDestroyingUse = getSingleDestroyingUse()) { - if (singleDestroyingUse->getUser() == beginInst) { - auto loc = RegularLocation::getAutoGeneratedLocation(); - SILBuilderWithScope builder(beginInst); - builder.createEndBorrow(loc, newGuaranteedValue); - return; - } - } - inst = beginInst; + analysis.emplace(cast(introducer.value), + getAllConsumingInsts()); + } else { + analysis.emplace(inst, getAllConsumingInsts()); } - ValueLifetimeAnalysis analysis(inst, getDestroyingInsts()); - bool foundCriticalEdges = !analysis.computeFrontier( + + // Use all consuming uses in our value lifetime analysis to ensure correctness + // in the face of unreachable code. + bool foundCriticalEdges = !analysis->computeFrontier( scratch, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks); (void)foundCriticalEdges; assert(!foundCriticalEdges); diff --git a/lib/SILOptimizer/Utils/ValueLifetime.cpp b/lib/SILOptimizer/Utils/ValueLifetime.cpp index 5fc8b0228b62b..4f90e9cc0bd80 100644 --- a/lib/SILOptimizer/Utils/ValueLifetime.cpp +++ b/lib/SILOptimizer/Utils/ValueLifetime.cpp @@ -11,17 +11,23 @@ //===----------------------------------------------------------------------===// #include "swift/SILOptimizer/Utils/ValueLifetime.h" +#include "swift/Basic/STLExtras.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SILOptimizer/Utils/CFGOptUtils.h" using namespace swift; void ValueLifetimeAnalysis::propagateLiveness() { + bool defIsInstruction = defValue.is(); assert(liveBlocks.empty() && "frontier computed twice"); - assert(!userSet.count(defValue) && "definition cannot be its own use"); + assert( + (!defIsInstruction || !userSet.count(defValue.get())) && + "definition cannot be its own use"); - auto defBB = defValue->getParentBlock(); - llvm::SmallVector worklist; + // Compute the def block only if we have a SILInstruction. If we have a + // SILArgument, this will be nullptr. + auto *defBB = getDefValueParentBlock(); + SmallVector worklist; int numUsersBeforeDef = 0; // Find the initial set of blocks where the value is live, because @@ -31,20 +37,28 @@ void ValueLifetimeAnalysis::propagateLiveness() { if (liveBlocks.insert(userBlock)) worklist.push_back(userBlock); - // A user in the defBB could potentially be located before the defValue. - if (userBlock == defBB) + // A user in the defBB could potentially be located before the defValue. If + // we had a SILArgument, defBB will be nullptr, so we should always have + // numUsersBeforeDef is 0. We assert this at the end of the loop. + if (defIsInstruction && userBlock == defBB) ++numUsersBeforeDef; } - // Don't count any users in the defBB which are actually located _after_ - // the defValue. - auto instIter = defValue->getIterator(); - while (numUsersBeforeDef > 0 && ++instIter != defBB->end()) { - if (userSet.count(&*instIter)) - --numUsersBeforeDef; + assert((defValue.is() || (numUsersBeforeDef == 0)) && + "Non SILInstruction defValue with users before the def?!"); + + // Don't count any users in the defBB which are actually located _after_ the + // defValue. + if (defIsInstruction) { + auto instIter = defValue.get()->getIterator(); + while (numUsersBeforeDef > 0 && ++instIter != defBB->end()) { + if (userSet.count(&*instIter)) + --numUsersBeforeDef; + } } // Initialize the hasUsersBeforeDef field. hasUsersBeforeDef = numUsersBeforeDef > 0; + assert(defIsInstruction || !hasUsersBeforeDef); // Now propagate liveness backwards until we hit the block that defines the // value. @@ -55,30 +69,31 @@ void ValueLifetimeAnalysis::propagateLiveness() { if (bb == defBB && !hasUsersBeforeDef) continue; - for (SILBasicBlock *Pred : bb->getPredecessorBlocks()) { + for (auto *predBB : bb->getPredecessorBlocks()) { // If it's already in the set, then we've already queued and/or // processed the predecessors. - if (liveBlocks.insert(Pred)) - worklist.push_back(Pred); + if (liveBlocks.insert(predBB)) + worklist.push_back(predBB); } } } SILInstruction *ValueLifetimeAnalysis::findLastUserInBlock(SILBasicBlock *bb) { // Walk backwards in bb looking for last use of the value. - for (auto ii = bb->rbegin(); ii != bb->rend(); ++ii) { - assert(defValue != &*ii && "Found def before finding use!"); + for (auto &inst : llvm::reverse(*bb)) { + assert(defValue.dyn_cast() != &inst && + "Found def before finding use!"); - if (userSet.count(&*ii)) - return &*ii; + if (userSet.count(&inst)) + return &inst; } llvm_unreachable("Expected to find use of value in block!"); } bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, DeadEndBlocks *deBlocks) { - assert(!isAliveAtBeginOfBlock(defValue->getFunction()->getEntryBlock()) - && "Can't compute frontier for def which does not dominate all uses"); + assert(!isAliveAtBeginOfBlock(getFunction()->getEntryBlock()) && + "Can't compute frontier for def which does not dominate all uses"); bool noCriticalEdges = true; @@ -101,10 +116,16 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, for (const SILSuccessor &succ : bb->getSuccessors()) { if (isAliveAtBeginOfBlock(succ)) { liveInSucc = true; - if (succ == defValue->getParent()) { + if (succ == getDefValueParentBlock()) { // Here, the basic block bb uses the value but also redefines the // value inside bb. The new value could be used by the successors // of succ and therefore could be live at the end of succ as well. + // + // This should never happen if we have a SILArgument since the + // SILArgument can not have any uses before it in a block. + assert(defValue.is() && + "SILArguments dominate all instructions in their defining " + "blocks"); usedAndRedefinedInSucc = true; } } else if (!deBlocks || !deBlocks->isDeadEnd(succ)) { @@ -115,7 +136,10 @@ bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, // Here, the basic block bb uses the value and later redefines the value. // Therefore, this value's lifetime ends after its last use preceding the // re-definition of the value. - auto ii = defValue->getReverseIterator(); + // + // We know that we can not have a SILArgument here since the SILArgument + // dominates all instructions in the same block. + auto ii = defValue.get()->getReverseIterator(); for (; ii != bb->rend(); ++ii) { if (userSet.count(&*ii)) { frontier.push_back(&*std::next(ii)); @@ -245,15 +269,19 @@ bool ValueLifetimeAnalysis::isWithinLifetime(SILInstruction *inst) { // Searches \p bb backwards from the instruction before \p frontierInst // to the beginning of the list and returns true if we find a dealloc_ref // /before/ we find \p defValue (the instruction that defines our target value). -static bool blockContainsDeallocRef(SILBasicBlock *bb, SILInstruction *defValue, - SILInstruction *frontierInst) { +static bool +blockContainsDeallocRef(SILBasicBlock *bb, + PointerUnion defValue, + SILInstruction *frontierInst) { SILBasicBlock::reverse_iterator End = bb->rend(); SILBasicBlock::reverse_iterator iter = frontierInst->getReverseIterator(); for (++iter; iter != End; ++iter) { SILInstruction *inst = &*iter; if (isa(inst)) return true; - if (inst == defValue) + // We know that inst is not a nullptr, so if we have a SILArgument, this + // will always fail as we want. + if (inst == defValue.dyn_cast()) return false; } return false; @@ -281,9 +309,14 @@ bool ValueLifetimeAnalysis::containsDeallocRef(const Frontier &frontier) { } void ValueLifetimeAnalysis::dump() const { - llvm::errs() << "lifetime of def: " << *defValue; - for (SILInstruction *Use : userSet) { - llvm::errs() << " use: " << *Use; + llvm::errs() << "lifetime of def: "; + if (auto *ii = defValue.dyn_cast()) { + llvm::errs() << *ii; + } else { + llvm::errs() << *defValue.get(); + } + for (SILInstruction *use : userSet) { + llvm::errs() << " use: " << *use; } llvm::errs() << " live blocks:"; for (SILBasicBlock *bb : liveBlocks) { diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil index aac4e3eb35ddf..ac0de9fae5479 100644 --- a/test/SILOptimizer/semantic-arc-opts.sil +++ b/test/SILOptimizer/semantic-arc-opts.sil @@ -32,7 +32,10 @@ protocol MyFakeAnyObject : Klass { func myFakeMethod() } -final class Klass {} +final class Klass { + var base: Klass +} + extension Klass : MyFakeAnyObject { func myFakeMethod() } @@ -1512,6 +1515,31 @@ bb3: return %9999 : $() } +// CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_with_leaked_enum_case : $@convention(thin) (@owned FakeOptional) -> () { +// CHECK-NOT: load [copy] +// CHECK: load_borrow +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'switch_enum_test_loadcopy_with_leaked_enum_case' +sil [ossa] @switch_enum_test_loadcopy_with_leaked_enum_case : $@convention(thin) (@owned FakeOptional) -> () { +bb0(%0 : @owned $FakeOptional): + %0a = alloc_stack $FakeOptional + store %0 to [init] %0a : $*FakeOptional + %1 = load [copy] %0a : $*FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 + +bb1(%2 : @owned $Builtin.NativeObject): + unreachable + +bb2: + br bb3 + +bb3: + destroy_addr %0a : $*FakeOptional + dealloc_stack %0a : $*FakeOptional + %9999 = tuple() + return %9999 : $() +} + // CHECK-LABEL: sil [ossa] @switch_enum_test_copyvalue_no_default : $@convention(thin) (@guaranteed FakeOptional) -> () { // CHECK-NOT: copy_value // CHECK: } // end sil function 'switch_enum_test_copyvalue_no_default' @@ -2568,3 +2596,46 @@ bb0(%0 : @guaranteed $Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObje %9999 = tuple() return %9999 : $() } + +// Make sure that we properly handle this case with out parameters and don't +// crash due to the SILArgument in bb3. +// +// CHECK-LABEL: sil [ossa] @iterated_transforming_terminator : $@convention(method) (@guaranteed Builtin.NativeObject) -> @out FakeOptional { +// CHECK-NOT: copy_value +// CHECK-NOT: @owned +// CHECK: } // end sil function 'iterated_transforming_terminator' +sil [ossa] @iterated_transforming_terminator : $@convention(method) (@guaranteed Builtin.NativeObject) -> @out FakeOptional { +bb0(%0 : $*FakeOptional, %1 : @guaranteed $Builtin.NativeObject): + %3 = init_enum_data_addr %0 : $*FakeOptional, #FakeOptional.some!enumelt + %4 = copy_value %1 : $Builtin.NativeObject + checked_cast_br %4 : $Builtin.NativeObject to Klass, bb1, bb2 + +bb1(%7 : @owned $Klass): + %8 = enum $FakeOptional, #FakeOptional.some!enumelt, %7 : $Klass + br bb3(%8 : $FakeOptional) + +bb2(%10 : @owned $Builtin.NativeObject): + destroy_value %10 : $Builtin.NativeObject + %12 = enum $FakeOptional, #FakeOptional.none!enumelt + br bb3(%12 : $FakeOptional) + +bb3(%14 : @owned $FakeOptional): + switch_enum %14 : $FakeOptional, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb6 + +bb4(%16 : @owned $Klass): + %17 = begin_borrow %16 : $Klass + %18 = ref_element_addr %17 : $Klass, #Klass.base + copy_addr %18 to [initialization] %3 : $*Klass + end_borrow %17 : $Klass + destroy_value %16 : $Klass + inject_enum_addr %0 : $*FakeOptional, #FakeOptional.some!enumelt + br bb5 + +bb5: + %24 = tuple () + return %24 : $() + +bb6: + inject_enum_addr %0 : $*FakeOptional, #FakeOptional.none!enumelt + br bb5 +} From 0ce281014464889b30ac1c807eb8c1a8106afce7 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 4 Aug 2020 14:47:15 +0900 Subject: [PATCH 054/663] [Serialization] Serialize subclassScope to keep linkage subclassScope was always set as NotApplicable when deserialized but we need to serialize and deserialize it to keep correct linkage when using SIB ```swift open class Visitor { public func visit() { visitExprImpl() } @_optimize(none) private func visitExprImpl() { } } ``` In this case, `visitExprImpl` is private but subclassScope is External. So it should be lowered as an external function at LLVM IR level. But once it's serialized into SIB, subclassScope of `visitExprImpl` was deserialized as NotApplicable because it was not serialized. This mismatch makes `visitExprImpl` lowered as an internal function at LLVM IR level. So `subclassScope` should be serialized. --- lib/Serialization/DeserializeSIL.cpp | 23 +++++++++++------------ lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SILFormat.h | 1 + lib/Serialization/SerializeSIL.cpp | 10 +++++----- test/Serialization/access-level.swift | 19 +++++++++++++++++++ 5 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 test/Serialization/access-level.swift diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 97c84001d009c..d6524751b765f 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -511,17 +511,16 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), + optimizationMode, subclassScope, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, - funcTyID, replacedFunctionID, genericSigID, + optimizationMode, subclassScope, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), + isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); if (funcTyID == 0) { @@ -645,6 +644,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setEffectsKind(EffectsKind(effect)); fn->setOptimizationMode(OptimizationMode(optimizationMode)); fn->setAlwaysWeakImported(isWeakImported); + fn->setClassSubclassScope(SubclassScope(subclassScope)); llvm::VersionTuple available; DECODE_VER_TUPLE(available); @@ -2830,17 +2830,16 @@ bool SILDeserializer::hasSILFunction(StringRef Name, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), + optimizationMode, subclassScope, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, - optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, - isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, - funcTyID, replacedFunctionID, genericSigID, + optimizationMode, subclassScope, effect, numSpecAttrs, + hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), + isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangOwnerID, SemanticsIDs); auto linkage = fromStableSILLinkage(rawLinkage); if (!linkage) { diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index b3a7a893f0932..6c2cf423887f7 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 568; // removed UTF16 +const uint16_t SWIFTMODULE_VERSION_MINOR = 569; // subclass scope /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index dfa1ea155b886..1f572f01c127a 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -281,6 +281,7 @@ namespace sil_block { BCFixed<3>, // specialPurpose BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode + BCFixed<2>, // classSubclassScope BCFixed<3>, // side effect info. BCVBR<8>, // number of specialize attributes BCFixed<1>, // has qualified ownership diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 00e9443213ea0..ba350bffefba1 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -435,11 +435,11 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), (unsigned)F.isAsync(), (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), - (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, - (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), - LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), - (unsigned)F.isExactSelfClass(), FnID, replacedFunctionID, genericSigID, - clangNodeOwnerID, SemanticsIDs); + (unsigned)F.getClassSubclassScope(), (unsigned)F.getEffectsKind(), + (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), + F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), + (unsigned)F.isDynamicallyReplaceable(), (unsigned)F.isExactSelfClass(), + FnID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); if (NoBody) return; diff --git a/test/Serialization/access-level.swift b/test/Serialization/access-level.swift new file mode 100644 index 0000000000000..5b098fb83f00e --- /dev/null +++ b/test/Serialization/access-level.swift @@ -0,0 +1,19 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s --check-prefix DIRECT-CHECK +// RUN: %target-swift-frontend -emit-sib %s -o %t/access-level.sib +// RUN: %target-swift-frontend -emit-ir %t/access-level.sib | %FileCheck %s --check-prefix FROM-SIB-CHECK + +// Ensure that the method linkage is default external when lowered from .swift directly +// DIRECT-CHECK-NOT: define{{.*}}internal{{.*}}swiftcc{{.*}}void @"$s4main7VisitorC13visitExprImpl33_205B03B83823935B4865F4617387553BLLyyF" + +// Ensure that the method linkage is default external when lowered from .swift -> .sib -> .ll +// FROM-SIB-CHECK-NOT: define{{.*}}internal{{.*}}swiftcc{{.*}}void @"$s4main7VisitorC13visitExprImpl33_205B03B83823935B4865F4617387553BLLyyF" + +open class Visitor { + public func visit() { + visitExprImpl() + } + @_optimize(none) + private func visitExprImpl() { + } +} From 0ca845818974d5ac9183dc05981d86d12434e5b4 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Sat, 8 Aug 2020 01:02:40 -0700 Subject: [PATCH 055/663] [NFC] Remove caching for "isOverlay" computation when emitting a trace. Based on measurements, it seemed to save about 0.2 ms - 0.4 ms for a module with a large number of imports from the SDK. That's insignificant compared to the compile time for a typical module, which usually takes somewhere between a few seconds and a few minutes. --- lib/FrontendTool/FrontendTool.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7cd611d221557..7784d45a73ce6 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -328,9 +328,6 @@ class ABIDependencyEvaluator { llvm::DenseSet visited; - /// Cache to avoid recomputing public imports of Swift modules repeatedly. - llvm::DenseMap isOverlayCache; - /// Helper function to handle invariant violations as crashes in debug mode. void crashOnInvariantViolation( llvm::function_ref f) const; @@ -484,10 +481,6 @@ void ABIDependencyEvaluator::reexposeImportedABI( bool ABIDependencyEvaluator::isOverlayOfClangModule(ModuleDecl *swiftModule) { assert(!swiftModule->isNonSwiftModule()); - auto cacheEntry = isOverlayCache.find(swiftModule); - if (cacheEntry != isOverlayCache.end()) - return cacheEntry->second; - llvm::SmallPtrSet importList; ::getImmediateImports(swiftModule, importList, {ModuleDecl::ImportFilterKind::Public}); @@ -495,7 +488,6 @@ bool ABIDependencyEvaluator::isOverlayOfClangModule(ModuleDecl *swiftModule) { llvm::any_of(importList, [&](ModuleDecl *importedModule) -> bool { return isClangOverlayOf(swiftModule, importedModule); }); - isOverlayCache[swiftModule] = isOverlay; return isOverlay; } From 80135c913a43ee9c6a05d1f81698acf2be927171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez=20Troiti=C3=B1o?= Date: Sun, 9 Aug 2020 17:24:17 -0700 Subject: [PATCH 056/663] [android] Adapt test to upstream readobj output change. This is a change that will be necessary for master-next. readobj seems to report elf32-littlearm when compiling for Android ARMv7. This is similar to commit f7cf5bde468e29ebe8239fbea53af39e7ecf4f5d which is still available in master-next, but I think was (mistakenly) reverted with #32265. --- test/DebugInfo/modulecache.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/DebugInfo/modulecache.swift b/test/DebugInfo/modulecache.swift index 5ddb4e800318d..1dceafbf15de1 100644 --- a/test/DebugInfo/modulecache.swift +++ b/test/DebugInfo/modulecache.swift @@ -16,7 +16,7 @@ import ClangModule // RUN: %empty-directory(%t) // RUN: %target-swift-frontend %s -c -g -o %t.o -module-cache-path %t -I %S/Inputs // RUN: llvm-readobj -h %t/*/ClangModule-*.pcm | %FileCheck %s -// CHECK: Format: {{(Mach-O|ELF|COFF)}} +// CHECK: Format: {{(Mach-O|ELF|elf64|COFF|elf32-littlearm)}} // 3. Test that swift-ide-check will not share swiftc's module cache. From 34c55e2d99509c826a1af599c7eaf357e9ec938a Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Fri, 7 Aug 2020 12:58:16 -0300 Subject: [PATCH 057/663] Add functionality that returns correct reflection section name for different object files --- include/swift/ABI/ObjectFile.h | 99 ++++++++++++++++++++ include/swift/Reflection/ReflectionContext.h | 64 ++++++++----- 2 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 include/swift/ABI/ObjectFile.h diff --git a/include/swift/ABI/ObjectFile.h b/include/swift/ABI/ObjectFile.h new file mode 100644 index 0000000000000..cd570132cdc0a --- /dev/null +++ b/include/swift/ABI/ObjectFile.h @@ -0,0 +1,99 @@ +//===--- ObjectFile.h - Object File Related Information ------*- C++ -*-===// +// +// Object File related data structures. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_ABI_OBJECTFILE_H +#define SWIFT_ABI_OBJECTFILE_H + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/StringRef.h" + +namespace swift { + +/// Represents the six reflection sections used by Swift +enum ReflectionSectionKind : uint8_t { + fieldmd, + assocty, + builtin, + capture, + typeref, + reflstr +}; + +/// Abstract base class responsible for providing the correct reflection section +/// string identifier for a given object file type (Mach-O, ELF, COFF). +class SwiftObjectFileFormat { +public: + virtual ~SwiftObjectFileFormat() {} + virtual llvm::StringRef getSectionName(ReflectionSectionKind section) = 0; +}; + +/// Responsible for providing the Mach-O reflection section identifiers. +class SwiftObjectFileFormatMachO : SwiftObjectFileFormat { +public: + llvm::StringRef getSectionName(ReflectionSectionKind section) override { + switch (section) { + case fieldmd: + return "__swift5_fieldmd"; + case assocty: + return "__swift5_assocty"; + case builtin: + return "__swift5_builtin"; + case capture: + return "__swift5_capture"; + case typeref: + return "__swift5_typeref"; + case reflstr: + return "__swift5_reflstr"; + } + llvm_unreachable("Section type not found."); + } +}; + +/// Responsible for providing the ELF reflection section identifiers. +class SwiftObjectFileFormatELF : SwiftObjectFileFormat { +public: + llvm::StringRef getSectionName(ReflectionSectionKind section) override { + switch (section) { + case fieldmd: + return "swift5_fieldmd"; + case assocty: + return "swift5_assocty"; + case builtin: + return "swift5_builtin"; + case capture: + return "swift5_capture"; + case typeref: + return "swift5_typeref"; + case reflstr: + return "swift5_reflstr"; + } + llvm_unreachable("Section type not found."); + } +}; + +/// Responsible for providing the COFF reflection section identifiers +class SwiftObjectFileFormatCOFF : SwiftObjectFileFormat { +public: + llvm::StringRef getSectionName(ReflectionSectionKind section) override { + switch (section) { + case fieldmd: + return ".sw5flmd"; + case assocty: + return ".sw5asty"; + case builtin: + return ".sw5bltn"; + case capture: + return ".sw5cptr"; + case typeref: + return ".sw5tyrf"; + case reflstr: + return ".sw5rfst"; + } + llvm_unreachable("Section not found."); + } +}; +} // namespace swift +#endif // SWIFT_ABI_OBJECTFILE_H diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 286aee8842b92..8fd1b571f1808 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -24,6 +24,7 @@ #include "llvm/Object/COFF.h" #include "swift/ABI/Enum.h" +#include "swift/ABI/ObjectFile.h" #include "swift/Remote/MemoryReader.h" #include "swift/Remote/MetadataReader.h" #include "swift/Reflection/Records.h" @@ -210,12 +211,12 @@ class ReflectionContext auto SectBuf = this->getReader().readBytes(RemoteAddress(RangeStart), RangeEnd - RangeStart); - auto findMachOSectionByName = [&](std::string Name) + auto findMachOSectionByName = [&](llvm::StringRef Name) -> std::pair, uint64_t> { for (unsigned I = 0; I < NumSect; ++I) { auto S = reinterpret_cast( SectionsBuf + (I * sizeof(typename T::Section))); - if (strncmp(S->sectname, Name.c_str(), strlen(Name.c_str())) != 0) + if (strncmp(S->sectname, Name.data(), strlen(Name.data())) != 0) continue; auto RemoteSecStart = S->addr + Slide; auto SectBufData = reinterpret_cast(SectBuf.get()); @@ -228,12 +229,19 @@ class ReflectionContext return {nullptr, 0}; }; - auto FieldMdSec = findMachOSectionByName("__swift5_fieldmd"); - auto AssocTySec = findMachOSectionByName("__swift5_assocty"); - auto BuiltinTySec = findMachOSectionByName("__swift5_builtin"); - auto CaptureSec = findMachOSectionByName("__swift5_capture"); - auto TypeRefMdSec = findMachOSectionByName("__swift5_typeref"); - auto ReflStrMdSec = findMachOSectionByName("__swift5_reflstr"); + SwiftObjectFileFormatMachO ObjectFileFormat; + auto FieldMdSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd)); + auto AssocTySec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty)); + auto BuiltinTySec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin)); + auto CaptureSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture)); + auto TypeRefMdSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref)); + auto ReflStrMdSec = findMachOSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); if (FieldMdSec.first == nullptr && AssocTySec.first == nullptr && @@ -330,12 +338,19 @@ class ReflectionContext return {nullptr, 0}; }; - auto CaptureSec = findCOFFSectionByName(".sw5cptr"); - auto TypeRefMdSec = findCOFFSectionByName(".sw5tyrf"); - auto FieldMdSec = findCOFFSectionByName(".sw5flmd"); - auto AssocTySec = findCOFFSectionByName(".sw5asty"); - auto BuiltinTySec = findCOFFSectionByName(".sw5bltn"); - auto ReflStrMdSec = findCOFFSectionByName(".sw5rfst"); + SwiftObjectFileFormatCOFF ObjectFileFormat; + auto FieldMdSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd)); + auto AssocTySec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty)); + auto BuiltinTySec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin)); + auto CaptureSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture)); + auto TypeRefMdSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref)); + auto ReflStrMdSec = findCOFFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); if (FieldMdSec.first == nullptr && AssocTySec.first == nullptr && @@ -424,7 +439,7 @@ class ReflectionContext auto StrTabBuf = this->getReader().readBytes(StrTabStart, StrTabSize); auto StrTab = reinterpret_cast(StrTabBuf.get()); - auto findELFSectionByName = [&](std::string Name) + auto findELFSectionByName = [&](llvm::StringRef Name) -> std::pair, uint64_t> { // Now for all the sections, find their name. for (const typename T::Section *Hdr : SecHdrVec) { @@ -444,12 +459,19 @@ class ReflectionContext return {nullptr, 0}; }; - auto FieldMdSec = findELFSectionByName("swift5_fieldmd"); - auto AssocTySec = findELFSectionByName("swift5_assocty"); - auto BuiltinTySec = findELFSectionByName("swift5_builtin"); - auto CaptureSec = findELFSectionByName("swift5_capture"); - auto TypeRefMdSec = findELFSectionByName("swift5_typeref"); - auto ReflStrMdSec = findELFSectionByName("swift5_reflstr"); + SwiftObjectFileFormatELF ObjectFileFormat; + auto FieldMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd)); + auto AssocTySec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty)); + auto BuiltinTySec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin)); + auto CaptureSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture)); + auto TypeRefMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref)); + auto ReflStrMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); // We succeed if at least one of the sections is present in the // ELF executable. From 52591ef9822b90f7f02994cee6baab7f4f8ad5db Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 13:41:24 -0700 Subject: [PATCH 058/663] [Sema] Rename error-handling code to effects-handling code. The error-handling code is getting generalized for 'async' handling as well, so rename the various entry points to talk about "effects" instead. --- lib/Sema/CMakeLists.txt | 2 +- lib/Sema/PCMacro.cpp | 4 +- lib/Sema/PlaygroundTransform.cpp | 6 +-- lib/Sema/TypeCheckDecl.cpp | 2 +- lib/Sema/TypeCheckDeclPrimary.cpp | 4 +- ...ypeCheckError.cpp => TypeCheckEffects.cpp} | 52 +++++++++---------- lib/Sema/TypeCheckStmt.cpp | 4 +- lib/Sema/TypeCheckStorage.cpp | 2 +- lib/Sema/TypeChecker.h | 10 ++-- 9 files changed, 43 insertions(+), 43 deletions(-) rename lib/Sema/{TypeCheckError.cpp => TypeCheckEffects.cpp} (97%) diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 3c0e373e81c6b..be48c2a9918e4 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -46,7 +46,7 @@ add_swift_host_library(swiftSema STATIC TypeCheckDeclObjC.cpp TypeCheckDeclOverride.cpp TypeCheckDeclPrimary.cpp - TypeCheckError.cpp + TypeCheckEffects.cpp TypeCheckExpr.cpp TypeCheckExprObjC.cpp TypeCheckGeneric.cpp diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 5d6075ef5b031..0ce8b28ac54a9 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -354,7 +354,7 @@ class Instrumenter : InstrumenterBase { if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -695,7 +695,7 @@ void swift::performPCMacro(SourceFile &SF) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); TypeChecker::contextualizeTopLevelCode(TLCD); } return false; diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 7c7e9dcd1e39b..f36294ff47240 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -294,7 +294,7 @@ class Instrumenter : InstrumenterBase { BraceStmt *NB = transformBraceStmt(B); if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -893,7 +893,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body); if (NewBody != Body) { FD->setBody(NewBody); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } return false; } @@ -905,7 +905,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); } return false; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d8fb606a5c388..c364de02f8eb0 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1066,7 +1066,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, if (TypeChecker::typeCheckExpression(exprToCheck, ED, rawTy, CTP_EnumCaseRawValue)) { - TypeChecker::checkEnumElementErrorHandling(elt, exprToCheck); + TypeChecker::checkEnumElementEffects(elt, exprToCheck); } } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index c307cca174ce5..7c4881e8d2305 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -881,7 +881,7 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); } - TypeChecker::checkInitializerErrorHandling(dc, initExpr); + TypeChecker::checkInitializerEffects(dc, initExpr); // Walk the checked initializer and contextualize any closures // we saw there. @@ -1657,7 +1657,7 @@ class DeclChecker : public DeclVisitor { PBD->getInitContext(i)); if (initContext) { // Check safety of error-handling in the declaration, too. - TypeChecker::checkInitializerErrorHandling(initContext, init); + TypeChecker::checkInitializerEffects(initContext, init); TypeChecker::contextualizeInitializer(initContext, init); } } diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckEffects.cpp similarity index 97% rename from lib/Sema/TypeCheckError.cpp rename to lib/Sema/TypeCheckEffects.cpp index 92819337f75dc..26e96a73c12c6 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1,4 +1,4 @@ -//===--- TypeCheckError.cpp - Type Checking for Error Coverage ------------===// +//===--- TypeCheckEffects.cpp - Type Checking for Effects Coverage --------===// // // This source file is part of the Swift.org open source project // @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis to ensure that errors are -// caught. +// This file implements semantic analysis to ensure that various effects (such +// as throwing and async) are properly handled. // //===----------------------------------------------------------------------===// @@ -184,9 +184,9 @@ enum ShouldRecurse_t : bool { }; /// A CRTP ASTWalker implementation that looks for interesting -/// nodes for error handling. +/// nodes for effects handling. template -class ErrorHandlingWalker : public ASTWalker { +class EffectsHandlingWalker : public ASTWalker { Impl &asImpl() { return *static_cast(this); } public: bool walkToDeclPre(Decl *D) override { @@ -221,7 +221,7 @@ class ErrorHandlingWalker : public ASTWalker { } else if (auto interpolated = dyn_cast(E)) { recurse = asImpl().checkInterpolatedStringLiteral(interpolated); } - // Error handling validation (via checkTopLevelErrorHandling) happens after + // Error handling validation (via checkTopLevelEffects) happens after // type checking. If an unchecked expression is still around, the code was // invalid. #define UNCHECKED_EXPR(KIND, BASE) \ @@ -580,7 +580,7 @@ class ApplyClassifier { } class FunctionBodyClassifier - : public ErrorHandlingWalker { + : public EffectsHandlingWalker { ApplyClassifier &Self; public: bool IsInvalid = false; @@ -1221,8 +1221,8 @@ class Context { /// A class to walk over a local context and validate the correctness /// of its error coverage. -class CheckErrorCoverage : public ErrorHandlingWalker { - friend class ErrorHandlingWalker; +class CheckEffectsCoverage : public EffectsHandlingWalker { + friend class EffectsHandlingWalker; ASTContext &Ctx; @@ -1288,13 +1288,13 @@ class CheckErrorCoverage : public ErrorHandlingWalker { /// An RAII object for restoring all the interesting state in an /// error-coverage. class ContextScope { - CheckErrorCoverage &Self; + CheckEffectsCoverage &Self; Context OldContext; DeclContext *OldRethrowsDC; ContextFlags OldFlags; ThrowingKind OldMaxThrowingKind; public: - ContextScope(CheckErrorCoverage &self, Optional newContext) + ContextScope(CheckEffectsCoverage &self, Optional newContext) : Self(self), OldContext(self.CurContext), OldRethrowsDC(self.Classifier.RethrowsDC), OldFlags(self.Flags), @@ -1379,7 +1379,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { }; public: - CheckErrorCoverage(ASTContext &ctx, Context initialContext) + CheckEffectsCoverage(ASTContext &ctx, Context initialContext) : Ctx(ctx), CurContext(initialContext), MaxThrowingKind(ThrowingKind::None) { @@ -1528,8 +1528,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // Check the inactive regions of a #if block to disable warnings that may // be due to platform specific code. struct ConservativeThrowChecker : public ASTWalker { - CheckErrorCoverage &CEC; - ConservativeThrowChecker(CheckErrorCoverage &CEC) : CEC(CEC) {} + CheckEffectsCoverage &CEC; + ConservativeThrowChecker(CheckEffectsCoverage &CEC) : CEC(CEC) {} Expr *walkToExprPost(Expr *E) override { if (isa(E)) @@ -1694,9 +1694,9 @@ class CheckErrorCoverage : public ErrorHandlingWalker { } // end anonymous namespace -void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { +void TypeChecker::checkTopLevelEffects(TopLevelCodeDecl *code) { auto &ctx = code->getDeclContext()->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forTopLevelCode(code)); + CheckEffectsCoverage checker(ctx, Context::forTopLevelCode(code)); // In some language modes, we allow top-level code to omit 'try' marking. if (ctx.LangOpts.EnableThrowWithoutTry) @@ -1705,16 +1705,16 @@ void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { code->getBody()->walk(checker); } -void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { +void TypeChecker::checkFunctionEffects(AbstractFunctionDecl *fn) { #ifndef NDEBUG - PrettyStackTraceDecl debugStack("checking error handling for", fn); + PrettyStackTraceDecl debugStack("checking effects handling for", fn); #endif auto isDeferBody = isa(fn) && cast(fn)->isDeferBody(); auto context = isDeferBody ? Context::forDeferBody() : Context::forFunction(fn); auto &ctx = fn->getASTContext(); - CheckErrorCoverage checker(ctx, context); + CheckEffectsCoverage checker(ctx, context); // If this is a debugger function, suppress 'try' marking at the top level. if (fn->getAttrs().hasAttribute()) @@ -1728,14 +1728,14 @@ void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { superInit->walk(checker); } -void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, +void TypeChecker::checkInitializerEffects(Initializer *initCtx, Expr *init) { auto &ctx = initCtx->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forInitializer(initCtx)); + CheckEffectsCoverage checker(ctx, Context::forInitializer(initCtx)); init->walk(checker); } -/// Check the correctness of error handling within the given enum +/// Check the correctness of effects within the given enum /// element's raw value expression. /// /// The syntactic restrictions on such expressions should make it @@ -1743,15 +1743,15 @@ void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, /// ensures correctness if those restrictions are ever loosened, /// perhaps accidentally, and (2) allows the verifier to assert that /// all calls have been checked. -void TypeChecker::checkEnumElementErrorHandling(EnumElementDecl *elt, Expr *E) { +void TypeChecker::checkEnumElementEffects(EnumElementDecl *elt, Expr *E) { auto &ctx = elt->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forEnumElementInitializer(elt)); + CheckEffectsCoverage checker(ctx, Context::forEnumElementInitializer(elt)); E->walk(checker); } -void TypeChecker::checkPropertyWrapperErrorHandling( +void TypeChecker::checkPropertyWrapperEffects( PatternBindingDecl *binding, Expr *expr) { auto &ctx = binding->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forPatternBinding(binding)); + CheckEffectsCoverage checker(ctx, Context::forPatternBinding(binding)); expr->walk(checker); } diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 5de97e3012634..9b8af8759bab2 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1698,7 +1698,7 @@ static Type getFunctionBuilderType(FuncDecl *FD) { bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) { auto res = evaluateOrDefault(AFD->getASTContext().evaluator, TypeCheckFunctionBodyRequest{AFD}, true); - TypeChecker::checkFunctionErrorHandling(AFD); + TypeChecker::checkFunctionEffects(AFD); TypeChecker::computeCaptures(AFD); return res; } @@ -2152,7 +2152,7 @@ void TypeChecker::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) { BraceStmt *Body = TLCD->getBody(); StmtChecker(TLCD).typeCheckStmt(Body); TLCD->setBody(Body); - checkTopLevelErrorHandling(TLCD); + checkTopLevelEffects(TLCD); performTopLevelDeclDiagnostics(TLCD); } diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index eca917211a065..01c82f7583890 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -2491,7 +2491,7 @@ static void typeCheckSynthesizedWrapperInitializer( dyn_cast_or_null(pbd->getInitContext(i))) { TypeChecker::contextualizeInitializer(initializerContext, initializer); } - TypeChecker::checkPropertyWrapperErrorHandling(pbd, initializer); + TypeChecker::checkPropertyWrapperEffects(pbd, initializer); } static PropertyWrapperMutability::Value diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index cefdf503fc1f6..f551fda552249 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1147,11 +1147,11 @@ void diagnoseIfDeprecated(SourceRange SourceRange, void checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name); /// Check error handling in the given type-checked top-level code. -void checkTopLevelErrorHandling(TopLevelCodeDecl *D); -void checkFunctionErrorHandling(AbstractFunctionDecl *D); -void checkInitializerErrorHandling(Initializer *I, Expr *E); -void checkEnumElementErrorHandling(EnumElementDecl *D, Expr *expr); -void checkPropertyWrapperErrorHandling(PatternBindingDecl *binding, +void checkTopLevelEffects(TopLevelCodeDecl *D); +void checkFunctionEffects(AbstractFunctionDecl *D); +void checkInitializerEffects(Initializer *I, Expr *E); +void checkEnumElementEffects(EnumElementDecl *D, Expr *expr); +void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr); /// If an expression references 'self.init' or 'super.init' in an From a2dc034184ba8a2396a6208331a593d60e4ddc51 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 14:00:09 -0700 Subject: [PATCH 059/663] [Effects handling] Stop storing an ApplyClassifier as an instance. --- lib/Sema/TypeCheckEffects.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 26e96a73c12c6..b7d8fcbaae788 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1226,8 +1226,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ASTContext &Ctx; - ApplyClassifier Classifier; - + DeclContext *RethrowsDC = nullptr; Context CurContext; class ContextFlags { @@ -1296,7 +1295,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker public: ContextScope(CheckEffectsCoverage &self, Optional newContext) : Self(self), OldContext(self.CurContext), - OldRethrowsDC(self.Classifier.RethrowsDC), + OldRethrowsDC(self.RethrowsDC), OldFlags(self.Flags), OldMaxThrowingKind(self.MaxThrowingKind) { if (newContext) self.CurContext = *newContext; @@ -1306,7 +1305,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ContextScope &operator=(const ContextScope &) = delete; void enterSubFunction() { - Self.Classifier.RethrowsDC = nullptr; + Self.RethrowsDC = nullptr; } void enterTry() { @@ -1372,7 +1371,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ~ContextScope() { Self.CurContext = OldContext; - Self.Classifier.RethrowsDC = OldRethrowsDC; + Self.RethrowsDC = OldRethrowsDC; Self.Flags = OldFlags; Self.MaxThrowingKind = OldMaxThrowingKind; } @@ -1384,7 +1383,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker MaxThrowingKind(ThrowingKind::None) { if (auto rethrowsDC = initialContext.getRethrowsDC()) { - Classifier.RethrowsDC = rethrowsDC; + RethrowsDC = rethrowsDC; } } @@ -1494,7 +1493,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkApply(ApplyExpr *E) { // An apply expression is a potential throw site if the function throws. // But if the expression didn't type-check, suppress diagnostics. - auto classification = Classifier.classifyApply(E); + ApplyClassifier classifier; + classifier.RethrowsDC = RethrowsDC; + auto classification = classifier.classifyApply(E); checkThrowAsyncSite(E, /*requiresTry*/ true, classification); From 8083b2dcecc4ece284eaf5856e8124c6bb86ec39 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 14:03:50 -0700 Subject: [PATCH 060/663] [Effects handling] Rename PotentialReason -> PotentialThrowsReason. --- lib/Sema/TypeCheckEffects.cpp | 72 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index b7d8fcbaae788..15a3fb40feaab 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -253,7 +253,7 @@ class EffectsHandlingWalker : public ASTWalker { }; /// A potential reason why something might throw. -class PotentialReason { +class PotentialThrowReason { public: enum class Kind : uint8_t { /// The function throws unconditionally. @@ -275,21 +275,21 @@ class PotentialReason { Expr *TheExpression; Kind TheKind; - explicit PotentialReason(Kind kind) : TheKind(kind) {} + explicit PotentialThrowReason(Kind kind) : TheKind(kind) {} public: - static PotentialReason forRethrowsArgument(Expr *E) { - PotentialReason result(Kind::CallRethrowsWithExplicitThrowingArgument); + static PotentialThrowReason forRethrowsArgument(Expr *E) { + PotentialThrowReason result(Kind::CallRethrowsWithExplicitThrowingArgument); result.TheExpression = E; return result; } - static PotentialReason forDefaultArgument() { - return PotentialReason(Kind::CallRethrowsWithDefaultThrowingArgument); + static PotentialThrowReason forDefaultArgument() { + return PotentialThrowReason(Kind::CallRethrowsWithDefaultThrowingArgument); } - static PotentialReason forThrowingApply() { - return PotentialReason(Kind::CallThrows); + static PotentialThrowReason forThrowingApply() { + return PotentialThrowReason(Kind::CallThrows); } - static PotentialReason forThrow() { - return PotentialReason(Kind::Throw); + static PotentialThrowReason forThrow() { + return PotentialThrowReason(Kind::Throw); } Kind getKind() const { return TheKind; } @@ -321,16 +321,16 @@ enum class ThrowingKind { }; /// A type expressing the result of classifying whether a call or function -/// throws. +/// throws or is async. class Classification { bool IsInvalid = false; // The AST is malformed. Don't diagnose. bool IsAsync = false; ThrowingKind Result = ThrowingKind::None; - Optional Reason; + Optional Reason; public: Classification() : Result(ThrowingKind::None) {} - explicit Classification(ThrowingKind result, PotentialReason reason, + explicit Classification(ThrowingKind result, PotentialThrowReason reason, bool isAsync) : IsAsync(isAsync), Result(result) { if (result == ThrowingKind::Throws || @@ -341,7 +341,7 @@ class Classification { /// Return a classification saying that there's an unconditional /// throw site. - static Classification forThrow(PotentialReason reason, bool isAsync) { + static Classification forThrow(PotentialThrowReason reason, bool isAsync) { Classification result; result.Result = ThrowingKind::Throws; result.Reason = reason; @@ -363,7 +363,7 @@ class Classification { return result; } - static Classification forRethrowingOnly(PotentialReason reason) { + static Classification forRethrowingOnly(PotentialThrowReason reason) { Classification result; result.Result = ThrowingKind::RethrowingOnly; result.Reason = reason; @@ -378,7 +378,7 @@ class Classification { bool isInvalid() const { return IsInvalid; } ThrowingKind getResult() const { return Result; } - PotentialReason getThrowsReason() const { + PotentialThrowReason getThrowsReason() const { assert(getResult() == ThrowingKind::Throws || getResult() == ThrowingKind::RethrowingOnly); return *Reason; @@ -446,7 +446,7 @@ class ApplyClassifier { assert(args.size() > fnRef.getNumArgumentsForFullApply() && "partial application was throwing?"); - return Classification::forThrow(PotentialReason::forThrowingApply(), + return Classification::forThrow(PotentialThrowReason::forThrowingApply(), isAsync); } @@ -476,7 +476,7 @@ class ApplyClassifier { // Try to classify the implementation of functions that we have // local knowledge of. Classification result = - classifyThrowingFunctionBody(fnRef, PotentialReason::forThrowingApply()); + classifyThrowingFunctionBody(fnRef, PotentialThrowReason::forThrowingApply()); assert(result.getResult() != ThrowingKind::None && "body classification decided function was no-throw"); @@ -496,7 +496,7 @@ class ApplyClassifier { /// if the function is an autoclosure that simply doesn't throw at all. Classification classifyThrowingFunctionBody(const AbstractFunction &fn, - PotentialReason reason) { + PotentialThrowReason reason) { // If we're not checking a 'rethrows' context, we don't need to // distinguish between 'throws' and 'rethrows'. But don't even // trust 'throws' for autoclosures. @@ -517,7 +517,7 @@ class ApplyClassifier { } Classification classifyThrowingParameterBody(ParamDecl *param, - PotentialReason reason) { + PotentialThrowReason reason) { assert(param->getType() ->lookThroughAllOptionalTypes() ->castTo() @@ -542,7 +542,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractFunctionDecl *fn, - PotentialReason reason) { + PotentialThrowReason reason) { // Functions can't be rethrowing-only unless they're defined // within the rethrows context. if (!isLocallyDefinedInRethrowsContext(fn) || !fn->hasBody()) @@ -556,7 +556,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractClosureExpr *closure, - PotentialReason reason) { + PotentialThrowReason reason) { bool isAutoClosure = isa(closure); // Closures can't be rethrowing-only unless they're defined @@ -705,7 +705,7 @@ class ApplyClassifier { if (isa(arg)) { return classifyArgumentByType(arg->getType(), - PotentialReason::forDefaultArgument()); + PotentialThrowReason::forDefaultArgument()); } // If this argument is `nil` literal, it doesn't cause the call to throw. @@ -736,7 +736,7 @@ class ApplyClassifier { // parameter type included a throwing function type. return classifyArgumentByType( paramType, - PotentialReason::forRethrowsArgument(arg)); + PotentialThrowReason::forRethrowsArgument(arg)); } // FIXME: There's a case where we can end up with an ApplyExpr that @@ -751,7 +751,7 @@ class ApplyClassifier { if (!paramFnType || !paramFnType->isThrowing()) return Classification(); - PotentialReason reason = PotentialReason::forRethrowsArgument(arg); + PotentialThrowReason reason = PotentialThrowReason::forRethrowsArgument(arg); // TODO: partial applications? @@ -793,7 +793,7 @@ class ApplyClassifier { /// a throwing function in a way that is permitted to cause a /// 'rethrows' function to throw. static Classification classifyArgumentByType(Type paramType, - PotentialReason reason) { + PotentialThrowReason reason) { if (!paramType || paramType->hasError()) return Classification::forInvalidCode(); if (auto fnType = paramType->getAs()) { @@ -1022,18 +1022,18 @@ class Context { } static void maybeAddRethrowsNote(DiagnosticEngine &Diags, SourceLoc loc, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (reason.getKind()) { - case PotentialReason::Kind::Throw: + case PotentialThrowReason::Kind::Throw: llvm_unreachable("should already have been covered"); - case PotentialReason::Kind::CallThrows: + case PotentialThrowReason::Kind::CallThrows: // Already fully diagnosed. return; - case PotentialReason::Kind::CallRethrowsWithExplicitThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithExplicitThrowingArgument: Diags.diagnose(reason.getThrowingArgument()->getLoc(), diag::because_rethrows_argument_throws); return; - case PotentialReason::Kind::CallRethrowsWithDefaultThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithDefaultThrowingArgument: Diags.diagnose(loc, diag::because_rethrows_default_argument_throws); return; } @@ -1041,7 +1041,7 @@ class Context { } void diagnoseUncoveredThrowSite(ASTContext &ctx, ASTNode E, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { auto &Diags = ctx.Diags; auto message = diag::throwing_call_without_try; auto loc = E.getStartLoc(); @@ -1077,7 +1077,7 @@ class Context { // // Let's suggest couple of alternative fix-its // because complete context is unavailable. - if (reason.getKind() != PotentialReason::Kind::CallThrows) + if (reason.getKind() != PotentialThrowReason::Kind::CallThrows) return; Diags.diagnose(loc, diag::note_forgot_try) @@ -1090,7 +1090,7 @@ class Context { void diagnoseThrowInLegalContext(DiagnosticEngine &Diags, ASTNode node, bool isTryCovered, - const PotentialReason &reason, + const PotentialThrowReason &reason, Diag<> diagForThrow, Diag<> diagForThrowingCall, Diag<> diagForTrylessThrowingCall) { @@ -1119,7 +1119,7 @@ class Context { void diagnoseUnhandledThrowSite(DiagnosticEngine &Diags, ASTNode E, bool isTryCovered, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (getKind()) { case Kind::Handled: llvm_unreachable("throw site is handled!"); @@ -1558,7 +1558,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkThrow(ThrowStmt *S) { checkThrowAsyncSite(S, /*requiresTry*/ false, - Classification::forThrow(PotentialReason::forThrow(), + Classification::forThrow(PotentialThrowReason::forThrow(), /*async*/false)); return ShouldRecurse; } From 27102e2a997d3ccbf1614136692ab29908c206ed Mon Sep 17 00:00:00 2001 From: Dario Rexin Date: Mon, 10 Aug 2020 15:05:09 -0700 Subject: [PATCH 061/663] Don't build with stdlib assertions on Linux --- utils/build-presets.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 9eaa76a841a99..489c3aec9094d 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -786,7 +786,7 @@ llvm-install-components=llvm-cov;llvm-profdata;IndexStore;clang;clang-resource-h [preset: mixin_linux_installation] mixin-preset= - mixin_lightweight_assertions + mixin_lightweight_assertions,no-stdlib-asserts mixin_linux_install_components_with_clang llbuild From fbbb2bb2eeb8ca25ca5a5dedeefd68a26c3cdec4 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 15:25:48 -0700 Subject: [PATCH 062/663] [Effects handling] Eliminate Context::Kind::NonExhaustiveCatch. This kind was too specific to error handling; use a bit instead. --- lib/Sema/TypeCheckEffects.cpp | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 15a3fb40feaab..9fe57f11448a0 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -816,7 +816,7 @@ class ApplyClassifier { } }; -/// An error-handling context. +/// An context in which effects might be handled. class Context { public: enum class Kind : uint8_t { @@ -832,9 +832,6 @@ class Context { /// A non-throwing autoclosure. NonThrowingAutoClosure, - /// A non-exhaustive catch within a non-throwing function. - NonExhaustiveCatch, - /// A default argument expression. DefaultArgument, @@ -887,6 +884,7 @@ class Context { } Kind TheKind; + bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; @@ -956,10 +954,6 @@ class Context { return Context(kind); } - static Context forNonExhaustiveCatch(DoCatchStmt *S) { - return Context(Kind::NonExhaustiveCatch); - } - static Context forCatchPattern(CaseStmt *S) { return Context(Kind::CatchPattern); } @@ -1006,6 +1000,10 @@ class Context { return InterpolatedString; } + void setNonExhaustiveCatch(bool value) { + IsNonExhaustiveCatch = value; + } + static void diagnoseThrowInIllegalContext(DiagnosticEngine &Diags, ASTNode node, StringRef description) { @@ -1103,8 +1101,7 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - (getKind() == Kind::NonThrowingFunction || - getKind() == Kind::NonExhaustiveCatch)) { + getKind() == Kind::NonThrowingFunction) { DiagnoseErrorOnTry = true; return; } @@ -1136,6 +1133,14 @@ class Context { return; case Kind::NonThrowingFunction: + if (IsNonExhaustiveCatch) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonexhaustive_catch, + diag::throwing_call_in_nonexhaustive_catch, + diag::tryless_throwing_call_in_nonexhaustive_catch); + return; + } + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, @@ -1149,13 +1154,6 @@ class Context { diag::tryless_throwing_call_in_nonthrowing_autoclosure); return; - case Kind::NonExhaustiveCatch: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonexhaustive_catch, - diag::throwing_call_in_nonexhaustive_catch, - diag::tryless_throwing_call_in_nonexhaustive_catch); - return; - case Kind::EnumElementInitializer: diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); return; @@ -1193,14 +1191,12 @@ class Context { llvm_unreachable("try is handled!"); case Kind::NonThrowingFunction: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), diag::try_unhandled); - return; - - case Kind::NonExhaustiveCatch: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), - diag::try_unhandled_in_nonexhaustive_catch); + if (DiagnoseErrorOnTry) { + Diags.diagnose( + E->getTryLoc(), + IsNonExhaustiveCatch ? diag::try_unhandled_in_nonexhaustive_catch + : diag::try_unhandled); + } return; case Kind::NonThrowingAutoClosure: @@ -1441,7 +1437,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker // If the enclosing context doesn't handle anything, use a // specialized diagnostic about non-exhaustive catches. if (CurContext.handlesNothing()) { - scope.refineLocalContext(Context::forNonExhaustiveCatch(S)); + CurContext.setNonExhaustiveCatch(true); } S->getBody()->walk(*this); From f24b7636f9866ba74866de2f1a4c64424e7bb85e Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 15:37:35 -0700 Subject: [PATCH 063/663] [Effects handling] Simplify away getKindForFunctionBody(). Determining whether a given function or closure is throwing got a lot simpler since this code was written. Do the obvious thing. --- lib/Sema/TypeCheckEffects.cpp | 37 +++++++++++------------------------ 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 9fe57f11448a0..c76e0a4891203 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -855,26 +855,6 @@ class Context { }; private: - static Kind getKindForFunctionBody(Type type, unsigned numArgs) { - /// Determine whether calling a function of the specified type with the - /// specified number of arguments would throw. - if (!type) return Kind::Handled; - - assert(numArgs > 0); - while (true) { - auto fnType = type->getAs(); - if (!fnType) return Kind::Handled; - - if (fnType->getExtInfo().isThrowing()) - return Kind::Handled; - - if (--numArgs == 0) - return Kind::NonThrowingFunction; - - type = fnType->getResult(); - } - } - static Context getContextForPatternBinding(PatternBindingDecl *pbd) { if (!pbd->isStatic() && pbd->getDeclContext()->isTypeContext()) { return Context(Kind::IVarInitializer); @@ -924,8 +904,7 @@ class Context { } } - return Context(getKindForFunctionBody( - D->getInterfaceType(), D->getNumCurryLevels())); + return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction); } static Context forDeferBody() { @@ -948,10 +927,16 @@ class Context { } static Context forClosure(AbstractClosureExpr *E) { - auto kind = getKindForFunctionBody(E->getType(), 1); - if (kind != Kind::Handled && isa(E)) - kind = Kind::NonThrowingAutoClosure; - return Context(kind); + // Determine whether the closure has throwing function type. + bool closureTypeThrows = true; + if (auto closureType = E->getType()) { + if (auto fnType = closureType->getAs()) + closureTypeThrows = fnType->isThrowing(); + } + + return Context(closureTypeThrows ? Kind::Handled + : isa(E) ? Kind::NonThrowingAutoClosure + : Kind::NonThrowingFunction); } static Context forCatchPattern(CaseStmt *S) { From f40de805c66cf3182008d7bff83b76d256db90a7 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 15:58:55 -0700 Subject: [PATCH 064/663] [Effects handling] Eliminate Context::Kind::NonThrowingAutoClosure. --- lib/Sema/TypeCheckEffects.cpp | 47 ++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index c76e0a4891203..7b691fec8c6fd 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -829,9 +829,6 @@ class Context { /// A rethrowing function. RethrowingFunction, - /// A non-throwing autoclosure. - NonThrowingAutoClosure, - /// A default argument expression. DefaultArgument, @@ -864,12 +861,26 @@ class Context { } Kind TheKind; + Optional Function; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; - explicit Context(Kind kind) : TheKind(kind) {} + explicit Context(Kind kind, Optional function = None) + : TheKind(kind), Function(function) {} + + /// Whether this is an autoclosure. + bool isAutoClosure() const { + if (!Function) + return false; + + auto closure = Function->getAbstractClosureExpr(); + if (!closure) + return false; + + return isa(closure); + } public: static Context getHandled() { @@ -883,7 +894,7 @@ class Context { static Context forFunction(AbstractFunctionDecl *D) { if (D->getAttrs().hasAttribute()) { - Context result(Kind::RethrowingFunction); + Context result(Kind::RethrowingFunction, AnyFunctionRef(D)); result.RethrowsDC = D; return result; } @@ -904,7 +915,8 @@ class Context { } } - return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction); + return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction, + AnyFunctionRef(D)); } static Context forDeferBody() { @@ -935,8 +947,8 @@ class Context { } return Context(closureTypeThrows ? Kind::Handled - : isa(E) ? Kind::NonThrowingAutoClosure - : Kind::NonThrowingFunction); + : Kind::NonThrowingFunction, + AnyFunctionRef(E)); } static Context forCatchPattern(CaseStmt *S) { @@ -1086,7 +1098,8 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - getKind() == Kind::NonThrowingFunction) { + getKind() == Kind::NonThrowingFunction && + !isAutoClosure()) { DiagnoseErrorOnTry = true; return; } @@ -1126,19 +1139,20 @@ class Context { return; } + if (isAutoClosure()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonthrowing_autoclosure, + diag::throwing_call_in_nonthrowing_autoclosure, + diag::tryless_throwing_call_in_nonthrowing_autoclosure); + return; + } + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, diag::tryless_throwing_call_unhandled); return; - case Kind::NonThrowingAutoClosure: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonthrowing_autoclosure, - diag::throwing_call_in_nonthrowing_autoclosure, - diag::tryless_throwing_call_in_nonthrowing_autoclosure); - return; - case Kind::EnumElementInitializer: diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); return; @@ -1184,7 +1198,6 @@ class Context { } return; - case Kind::NonThrowingAutoClosure: case Kind::EnumElementInitializer: case Kind::GlobalVarInitializer: case Kind::IVarInitializer: From 7cee2bf4877d240546c2fa9fdc1d6114e0c16422 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 10 Aug 2020 16:23:56 -0700 Subject: [PATCH 065/663] Windows: include `direct.h` in `sys.stat` module On Unicies `sys/stat.h` will provide `mkdir`. Windows provides the POSIX requirement through the portable name `_mkdir` which is declared in the `direct.h` header. This adds the additional header to the `ucrt` module to allow access to this function. --- stdlib/public/Platform/ucrt.modulemap | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/public/Platform/ucrt.modulemap b/stdlib/public/Platform/ucrt.modulemap index 03fe87bf74451..2d88621038f4a 100644 --- a/stdlib/public/Platform/ucrt.modulemap +++ b/stdlib/public/Platform/ucrt.modulemap @@ -95,6 +95,7 @@ module ucrt [system] { module stat { header "sys/stat.h" + header "direct.h" export * } From 4096a62b2aa8947eafa0a1456508cf9181687b3b Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 10 Aug 2020 19:56:00 -0700 Subject: [PATCH 066/663] [ConstraintSystem] Don't update the work list when merging type variables in addJoinConstraint. --- lib/Sema/ConstraintSystem.h | 2 +- validation-test/SILOptimizer/large_string_array.swift.gyb | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 4e4924a0bc78b..2f3c275b32d5e 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3147,7 +3147,7 @@ class ConstraintSystem { if (originalRep) { if (originalRep != currentRep) - mergeEquivalenceClasses(currentRep, originalRep); + mergeEquivalenceClasses(currentRep, originalRep, /*updateWorkList=*/false); continue; } diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 91280bd424040..6285e4b97c75b 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -12,8 +12,6 @@ // REQUIRES: long_test // REQUIRES: CPU=arm64 || CPU=x86_64 -// REQUIRES: rdar66807959 - // Check if the optimizer can optimize the whole array into a statically // initialized global From 524887bb009735c3c5889b7eba16706c6d387df3 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 21:27:56 -0700 Subject: [PATCH 067/663] [Effects handling] Eliminate Context::Kind::RethrowingFunction. We can determine whether we have a rethrowing function based on the function declaration itself. --- lib/Sema/TypeCheckEffects.cpp | 67 +++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 7b691fec8c6fd..36bce683caca3 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -826,9 +826,6 @@ class Context { /// A non-throwing function. NonThrowingFunction, - /// A rethrowing function. - RethrowingFunction, - /// A default argument expression. DefaultArgument, @@ -864,12 +861,27 @@ class Context { Optional Function; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; - DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; explicit Context(Kind kind, Optional function = None) : TheKind(kind), Function(function) {} +public: + /// Whether this is a function that rethrows. + bool isRethrows() const { + if (getKind() != Kind::Handled) + return false; + + if (!Function) + return false; + + auto fn = Function->getAbstractFunctionDecl(); + if (!fn) + return false; + + return fn->getAttrs().hasAttribute(); + } + /// Whether this is an autoclosure. bool isAutoClosure() const { if (!Function) @@ -882,7 +894,6 @@ class Context { return isa(closure); } -public: static Context getHandled() { return Context(Kind::Handled); } @@ -893,12 +904,6 @@ class Context { } static Context forFunction(AbstractFunctionDecl *D) { - if (D->getAttrs().hasAttribute()) { - Context result(Kind::RethrowingFunction, AnyFunctionRef(D)); - result.RethrowsDC = D; - return result; - } - // HACK: If the decl is the synthesized getter for a 'lazy' property, then // treat the context as a property initializer in order to produce a better // diagnostic; the only code we should be diagnosing on is within the @@ -972,8 +977,7 @@ class Context { Kind getKind() const { return TheKind; } bool handlesNothing() const { - return getKind() != Kind::Handled && - getKind() != Kind::RethrowingFunction; + return getKind() != Kind::Handled; } bool handles(ThrowingKind errorKind) const { switch (errorKind) { @@ -982,17 +986,23 @@ class Context { // A call that's rethrowing-only can be handled by 'rethrows'. case ThrowingKind::RethrowingOnly: - return !handlesNothing(); + return getKind() == Kind::Handled; // An operation that always throws can only be handled by an // all-handling context. case ThrowingKind::Throws: - return getKind() == Kind::Handled; + return getKind() == Kind::Handled && !isRethrows(); } llvm_unreachable("bad error kind"); } - DeclContext *getRethrowsDC() const { return RethrowsDC; } + DeclContext *getRethrowsDC() const { + if (!isRethrows()) + return nullptr; + + return Function->getAbstractFunctionDecl(); + } + InterpolatedStringLiteralExpr * getInterpolatedString() const { return InterpolatedString; } @@ -1098,8 +1108,7 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - getKind() == Kind::NonThrowingFunction && - !isAutoClosure()) { + !isRethrows() && !isAutoClosure()) { DiagnoseErrorOnTry = true; return; } @@ -1117,18 +1126,15 @@ class Context { const PotentialThrowReason &reason) { switch (getKind()) { case Kind::Handled: - llvm_unreachable("throw site is handled!"); - - // TODO: Doug suggested that we could generate one error per - // non-throwing function with throw sites within it, possibly with - // notes for the throw sites. + if (isRethrows()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_rethrows_function, + diag::throwing_call_in_rethrows_function, + diag::tryless_throwing_call_in_rethrows_function); + return; + } - case Kind::RethrowingFunction: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_rethrows_function, - diag::throwing_call_in_rethrows_function, - diag::tryless_throwing_call_in_rethrows_function); - return; + llvm_unreachable("throw site is handled!"); case Kind::NonThrowingFunction: if (IsNonExhaustiveCatch) { @@ -1186,7 +1192,6 @@ class Context { void diagnoseUnhandledTry(DiagnosticEngine &Diags, TryExpr *E) { switch (getKind()) { case Kind::Handled: - case Kind::RethrowingFunction: llvm_unreachable("try is handled!"); case Kind::NonThrowingFunction: @@ -1471,7 +1476,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker auto savedContext = CurContext; if (doThrowingKind != ThrowingKind::Throws && - CurContext.getKind() == Context::Kind::RethrowingFunction) { + CurContext.isRethrows()) { // If this catch clause is reachable at all, it's because a function // parameter throws. So let's temporarily set our context to Handled so // the catch body is allowed to throw. From ea8217ad7eae8b259d914c27edaf38cefd613604 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 21:50:06 -0700 Subject: [PATCH 068/663] [Effects handling] Collapse "Handled" and "NonThrowingFunction" kinds. Finish eliminating error-handling-specific information from the "kind" of the effects-handling context, so that it only distinguishes between "potentially handles effects" and "never handles effects". Use queries for specific issues (e.g., "handles errors") instead. --- lib/Sema/TypeCheckEffects.cpp | 66 ++++++++++++++++------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 36bce683caca3..c291217d99270 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -820,11 +820,8 @@ class ApplyClassifier { class Context { public: enum class Kind : uint8_t { - /// A context that handles errors. - Handled, - - /// A non-throwing function. - NonThrowingFunction, + /// A context that potentially handles errors or async calls. + PotentiallyHandled, /// A default argument expression. DefaultArgument, @@ -859,17 +856,24 @@ class Context { Kind TheKind; Optional Function; + bool HandlesErrors = false; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; - explicit Context(Kind kind, Optional function = None) - : TheKind(kind), Function(function) {} + explicit Context(Kind kind) + : TheKind(kind), Function(None), HandlesErrors(false) { + assert(TheKind != Kind::PotentiallyHandled); + } + + explicit Context(bool handlesErrors, Optional function) + : TheKind(Kind::PotentiallyHandled), Function(function), + HandlesErrors(handlesErrors) { } public: /// Whether this is a function that rethrows. bool isRethrows() const { - if (getKind() != Kind::Handled) + if (!HandlesErrors) return false; if (!Function) @@ -895,12 +899,12 @@ class Context { } static Context getHandled() { - return Context(Kind::Handled); + return Context(/*handlesErrors=*/true, None); } static Context forTopLevelCode(TopLevelCodeDecl *D) { - // Top-level code implicitly handles errors. - return Context(Kind::Handled); + // Top-level code implicitly handles errors and 'async' calls. + return Context(/*handlesErrors=*/true, None); } static Context forFunction(AbstractFunctionDecl *D) { @@ -920,8 +924,8 @@ class Context { } } - return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction, - AnyFunctionRef(D)); + bool handlesErrors = D->hasThrows(); + return Context(handlesErrors, AnyFunctionRef(D)); } static Context forDeferBody() { @@ -951,9 +955,7 @@ class Context { closureTypeThrows = fnType->isThrowing(); } - return Context(closureTypeThrows ? Kind::Handled - : Kind::NonThrowingFunction, - AnyFunctionRef(E)); + return Context(closureTypeThrows, AnyFunctionRef(E)); } static Context forCatchPattern(CaseStmt *S) { @@ -977,7 +979,7 @@ class Context { Kind getKind() const { return TheKind; } bool handlesNothing() const { - return getKind() != Kind::Handled; + return !HandlesErrors; } bool handles(ThrowingKind errorKind) const { switch (errorKind) { @@ -986,12 +988,12 @@ class Context { // A call that's rethrowing-only can be handled by 'rethrows'. case ThrowingKind::RethrowingOnly: - return getKind() == Kind::Handled; + return HandlesErrors; // An operation that always throws can only be handled by an // all-handling context. case ThrowingKind::Throws: - return getKind() == Kind::Handled && !isRethrows(); + return HandlesErrors && !isRethrows(); } llvm_unreachable("bad error kind"); } @@ -1125,18 +1127,7 @@ class Context { bool isTryCovered, const PotentialThrowReason &reason) { switch (getKind()) { - case Kind::Handled: - if (isRethrows()) { - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_rethrows_function, - diag::throwing_call_in_rethrows_function, - diag::tryless_throwing_call_in_rethrows_function); - return; - } - - llvm_unreachable("throw site is handled!"); - - case Kind::NonThrowingFunction: + case Kind::PotentiallyHandled: if (IsNonExhaustiveCatch) { diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonexhaustive_catch, @@ -1153,6 +1144,14 @@ class Context { return; } + if (isRethrows()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_rethrows_function, + diag::throwing_call_in_rethrows_function, + diag::tryless_throwing_call_in_rethrows_function); + return; + } + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, @@ -1191,10 +1190,7 @@ class Context { void diagnoseUnhandledTry(DiagnosticEngine &Diags, TryExpr *E) { switch (getKind()) { - case Kind::Handled: - llvm_unreachable("try is handled!"); - - case Kind::NonThrowingFunction: + case Kind::PotentiallyHandled: if (DiagnoseErrorOnTry) { Diags.diagnose( E->getTryLoc(), From 90e42bbcd67a31771b301246f4a92c1ffc8fafd6 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 22:11:56 -0700 Subject: [PATCH 069/663] [Effects handling] Eliminate Context::getHandled(). We don't want to expose the notion of "handles everything", because that's a honeypot for messing up 'async' checking when making a context change for error-handling, and vice versa. Instead, provide an API to produce a derived context where all errors are handled, and use it for (e.g.) try/try!/try? and exhaustive do-catches. --- lib/Sema/TypeCheckEffects.cpp | 37 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index c291217d99270..bd8b3eeda3f20 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -857,6 +857,10 @@ class Context { Kind TheKind; Optional Function; bool HandlesErrors = false; + + /// Whether error-handling queries should ignore the function context, e.g., + /// for autoclosure and rethrows checks. + bool ErrorHandlingIgnoresFunction = false; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; @@ -876,6 +880,9 @@ class Context { if (!HandlesErrors) return false; + if (ErrorHandlingIgnoresFunction) + return false; + if (!Function) return false; @@ -891,6 +898,9 @@ class Context { if (!Function) return false; + if (ErrorHandlingIgnoresFunction) + return false; + auto closure = Function->getAbstractClosureExpr(); if (!closure) return false; @@ -898,10 +908,6 @@ class Context { return isa(closure); } - static Context getHandled() { - return Context(/*handlesErrors=*/true, None); - } - static Context forTopLevelCode(TopLevelCodeDecl *D) { // Top-level code implicitly handles errors and 'async' calls. return Context(/*handlesErrors=*/true, None); @@ -976,6 +982,15 @@ class Context { return copy; } + /// Form a subcontext that handles all errors, e.g., for the body of a + /// do-catch with exhaustive catch clauses. + Context withHandlesErrors() const { + Context copy = *this; + copy.HandlesErrors = true; + copy.ErrorHandlingIgnoresFunction = true; + return copy; + } + Kind getKind() const { return TheKind; } bool handlesNothing() const { @@ -1416,8 +1431,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker } ThrowingKind checkExhaustiveDoBody(DoCatchStmt *S) { - // This is a handled context. - ContextScope scope(*this, Context::getHandled()); + // This is a context where errors are handled. + ContextScope scope(*this, CurContext.withHandlesErrors()); assert(!Flags.has(ContextFlags::IsInTry) && "do/catch within try?"); scope.resetCoverageForDoCatch(); @@ -1474,9 +1489,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker if (doThrowingKind != ThrowingKind::Throws && CurContext.isRethrows()) { // If this catch clause is reachable at all, it's because a function - // parameter throws. So let's temporarily set our context to Handled so - // the catch body is allowed to throw. - CurContext = Context::getHandled(); + // parameter throws. So let's temporarily state that the body is allowed + // to throw. + CurContext = CurContext.withHandlesErrors(); } // The catch body just happens in the enclosing context. @@ -1661,7 +1676,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkForceTry(ForceTryExpr *E) { // Walk the operand. 'try!' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); @@ -1675,7 +1690,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkOptionalTry(OptionalTryExpr *E) { // Walk the operand. 'try?' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); From 462e37bbf527d6436f6b44f59862ae178603c618 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 22:26:51 -0700 Subject: [PATCH 070/663] [Effects handling] Move "illegal context" strings into diagnostic text. The "illegal context" diagnostics were passing strings from the C++ code directly into diagnostic text for things like "a default argument". That causes a bunch of duplicated code and defeats localization of diagnostics, so move to a %select in the diagnostic. --- include/swift/AST/DiagnosticsSema.def | 9 ++++++--- lib/Sema/TypeCheckEffects.cpp | 26 +++++--------------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index fc9b7f98dd2a0..f4364f6438b1e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4008,10 +4008,13 @@ ERROR(throw_in_nonexhaustive_catch,none, "error is not handled because the enclosing catch is not exhaustive", ()) ERROR(throwing_call_in_illegal_context,none, - "call can throw, but errors cannot be thrown out of %0", - (StringRef)) + "call can throw, but errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throw_in_illegal_context,none, - "errors cannot be thrown out of %0", (StringRef)) + "errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throwing_operator_without_try,none, "operator can throw but expression is not marked with 'try'", ()) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index bd8b3eeda3f20..69e7d578fee17 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1030,17 +1030,17 @@ class Context { static void diagnoseThrowInIllegalContext(DiagnosticEngine &Diags, ASTNode node, - StringRef description) { + Kind kind) { if (auto *e = node.dyn_cast()) { if (isa(e)) { Diags.diagnose(e->getLoc(), diag::throwing_call_in_illegal_context, - description); + static_cast(kind)); return; } } Diags.diagnose(node.getStartLoc(), diag::throw_in_illegal_context, - description); + static_cast(kind)); } static void maybeAddRethrowsNote(DiagnosticEngine &Diags, SourceLoc loc, @@ -1174,31 +1174,15 @@ class Context { return; case Kind::EnumElementInitializer: - diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); - return; - case Kind::GlobalVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a global variable initializer"); - return; - case Kind::IVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a property initializer"); - return; - case Kind::DefaultArgument: - diagnoseThrowInIllegalContext(Diags, E, "a default argument"); - return; - case Kind::CatchPattern: - diagnoseThrowInIllegalContext(Diags, E, "a catch pattern"); - return; - case Kind::CatchGuard: - diagnoseThrowInIllegalContext(Diags, E, "a catch guard expression"); - return; case Kind::DeferBody: - diagnoseThrowInIllegalContext(Diags, E, "a defer body"); + diagnoseThrowInIllegalContext(Diags, E, getKind()); return; + } llvm_unreachable("bad context kind"); } From 40c12cc9a7cbca943aac76fbba38f8bf9a1a77c1 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 23:30:57 -0700 Subject: [PATCH 071/663] [Concurrency] Implement restrictions on calls to 'async' functions. Implement missing restrictions on calls to 'async': * Diagnose async calls/uses of await in illegal contexts (such as default arguments) * Diagnose async calls/uses of await in functions/closures that are not asynchronous themselves * Handle autoclosure arguments as their own separate contexts (so 'await' has to go on the argument), which differs from error handling (where the 'try' can go outside) because we want to be more particular about marking the specific suspension points. --- include/swift/AST/DiagnosticsSema.def | 16 ++++ lib/Sema/TypeCheckEffects.cpp | 119 +++++++++++++++++++++----- test/expr/unary/async_await.swift | 40 +++++++++ 3 files changed, 153 insertions(+), 22 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d470965fbf400..ba013ef17706c 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4038,8 +4038,24 @@ NOTE(note_disable_error_propagation,none, "did you mean to disable error propagation?", ()) ERROR(async_call_without_await,none, "call is 'async' but is not marked with 'await'", ()) +ERROR(async_call_without_await_in_autoclosure,none, + "call is 'async' in an autoclosure argument is not marked with 'await'", ()) WARNING(no_async_in_await,none, "no calls to 'async' functions occur within 'await' expression", ()) +ERROR(async_call_in_illegal_context,none, + "'async' call cannot occur in " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) +ERROR(await_in_illegal_context,none, + "'await' operation cannot occur in " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) +ERROR(async_in_nonasync_function,none, + "%select{'async'|'await'}0 in %select{a function|an autoclosure}1 that " + "does not support concurrency", + (bool, bool)) +NOTE(note_add_async_to_function,none, + "add 'async' to function %0 to make it asynchronous", (DeclName)) WARNING(no_throw_in_try,none, "no calls to throwing functions occur within 'try' expression", ()) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 69e7d578fee17..7de3d6c5a8dc2 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -857,6 +857,7 @@ class Context { Kind TheKind; Optional Function; bool HandlesErrors = false; + bool HandlesAsync = false; /// Whether error-handling queries should ignore the function context, e.g., /// for autoclosure and rethrows checks. @@ -870,9 +871,10 @@ class Context { assert(TheKind != Kind::PotentiallyHandled); } - explicit Context(bool handlesErrors, Optional function) + explicit Context(bool handlesErrors, bool handlesAsync, + Optional function) : TheKind(Kind::PotentiallyHandled), Function(function), - HandlesErrors(handlesErrors) { } + HandlesErrors(handlesErrors), HandlesAsync(handlesAsync) { } public: /// Whether this is a function that rethrows. @@ -910,7 +912,7 @@ class Context { static Context forTopLevelCode(TopLevelCodeDecl *D) { // Top-level code implicitly handles errors and 'async' calls. - return Context(/*handlesErrors=*/true, None); + return Context(/*handlesErrors=*/true, /*handlesAsync=*/true, None); } static Context forFunction(AbstractFunctionDecl *D) { @@ -930,8 +932,7 @@ class Context { } } - bool handlesErrors = D->hasThrows(); - return Context(handlesErrors, AnyFunctionRef(D)); + return Context(D->hasThrows(), D->hasAsync(), AnyFunctionRef(D)); } static Context forDeferBody() { @@ -956,12 +957,15 @@ class Context { static Context forClosure(AbstractClosureExpr *E) { // Determine whether the closure has throwing function type. bool closureTypeThrows = true; + bool closureTypeIsAsync = true; if (auto closureType = E->getType()) { - if (auto fnType = closureType->getAs()) + if (auto fnType = closureType->getAs()) { closureTypeThrows = fnType->isThrowing(); + closureTypeIsAsync = fnType->isAsync(); + } } - return Context(closureTypeThrows, AnyFunctionRef(E)); + return Context(closureTypeThrows, closureTypeIsAsync, AnyFunctionRef(E)); } static Context forCatchPattern(CaseStmt *S) { @@ -1013,6 +1017,10 @@ class Context { llvm_unreachable("bad error kind"); } + bool handlesAsync() const { + return HandlesAsync; + } + DeclContext *getRethrowsDC() const { if (!isRethrows()) return nullptr; @@ -1182,7 +1190,6 @@ class Context { case Kind::DeferBody: diagnoseThrowInIllegalContext(Diags, E, getKind()); return; - } llvm_unreachable("bad context kind"); } @@ -1211,6 +1218,64 @@ class Context { } llvm_unreachable("bad context kind"); } + + void diagnoseUncoveredAsyncSite(ASTContext &ctx, ASTNode node) { + SourceRange highlight; + + // Generate more specific messages in some cases. + if (auto apply = dyn_cast_or_null(node.dyn_cast())) + highlight = apply->getSourceRange(); + + auto diag = diag::async_call_without_await; + if (isAutoClosure()) + diag = diag::async_call_without_await_in_autoclosure; + ctx.Diags.diagnose(node.getStartLoc(), diag) + .highlight(highlight); + } + + void diagnoseAsyncInIllegalContext(DiagnosticEngine &Diags, ASTNode node) { + if (auto *e = node.dyn_cast()) { + if (isa(e)) { + Diags.diagnose(e->getLoc(), diag::async_call_in_illegal_context, + static_cast(getKind())); + return; + } + } + + Diags.diagnose(node.getStartLoc(), diag::await_in_illegal_context, + static_cast(getKind())); + } + + void maybeAddAsyncNote(DiagnosticEngine &Diags) { + if (!Function) + return; + + auto func = dyn_cast_or_null(Function->getAbstractFunctionDecl()); + if (!func) + return; + + func->diagnose(diag::note_add_async_to_function, func->getName()); + } + + void diagnoseUnhandledAsyncSite(DiagnosticEngine &Diags, ASTNode node) { + switch (getKind()) { + case Kind::PotentiallyHandled: + Diags.diagnose(node.getStartLoc(), diag::async_in_nonasync_function, + node.isExpr(ExprKind::Await), isAutoClosure()); + maybeAddAsyncNote(Diags); + return; + + case Kind::EnumElementInitializer: + case Kind::GlobalVarInitializer: + case Kind::IVarInitializer: + case Kind::DefaultArgument: + case Kind::CatchPattern: + case Kind::CatchGuard: + case Kind::DeferBody: + diagnoseAsyncInIllegalContext(Diags, node); + return; + } + } }; /// A class to walk over a local context and validate the correctness @@ -1322,6 +1387,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker Self.MaxThrowingKind = ThrowingKind::None; } + void resetCoverageForAutoclosureBody() { + Self.Flags.clear(ContextFlags::IsAsyncCovered); + Self.Flags.clear(ContextFlags::HasAnyAsyncSite); + Self.Flags.clear(ContextFlags::HasAnyAwait); + } + void resetCoverageForDoCatch() { Self.Flags.reset(); Self.MaxThrowingKind = ThrowingKind::None; @@ -1409,6 +1480,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkAutoClosure(AutoClosureExpr *E) { ContextScope scope(*this, Context::forClosure(E)); scope.enterSubFunction(); + scope.resetCoverageForAutoclosureBody(); E->getBody()->walk(*this); scope.preserveCoverageFromAutoclosureBody(); return ShouldNotRecurse; @@ -1572,17 +1644,14 @@ class CheckEffectsCoverage : public EffectsHandlingWalker if (classification.isAsync()) { // Remember that we've seen an async call. Flags.set(ContextFlags::HasAnyAsyncSite); - + + // Diagnose async calls in a context that doesn't handle async. + if (!CurContext.handlesAsync()) { + CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, E); + } // Diagnose async calls that are outside of an await context. - if (!Flags.has(ContextFlags::IsAsyncCovered)) { - SourceRange highlight; - - // Generate more specific messages in some cases. - if (auto e = dyn_cast_or_null(E.dyn_cast())) - highlight = e->getSourceRange(); - - Ctx.Diags.diagnose(E.getStartLoc(), diag::async_call_without_await) - .highlight(highlight); + else if (!Flags.has(ContextFlags::IsAsyncCovered)) { + CurContext.diagnoseUncoveredAsyncSite(Ctx, E); } } @@ -1626,10 +1695,16 @@ class CheckEffectsCoverage : public EffectsHandlingWalker scope.enterAwait(); E->getSubExpr()->walk(*this); - - // Warn about 'await' expressions that weren't actually needed. - if (!Flags.has(ContextFlags::HasAnyAsyncSite)) - Ctx.Diags.diagnose(E->getAwaitLoc(), diag::no_async_in_await); + + // Warn about 'await' expressions that weren't actually needed, unless of + // course we're in a context that could never handle an 'async'. Then, we + // produce an error. + if (!Flags.has(ContextFlags::HasAnyAsyncSite)) { + if (CurContext.handlesAsync()) + Ctx.Diags.diagnose(E->getAwaitLoc(), diag::no_async_in_await); + else + CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, E); + } // Inform the parent of the walk that an 'await' exists here. scope.preserveCoverageFromAwaitOperand(); diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index 2ab75eae60eb4..e3de627591095 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -8,3 +8,43 @@ func test1(asyncfp : () async -> Int, fp : () -> Int) async { _ = asyncfp() // expected-error {{call is 'async' but is not marked with 'await'}} } +func getInt() async -> Int { return 5 } + +// Locations where "await" is prohibited. +func test2( + defaulted: Int = __await getInt() // expected-error{{'async' call cannot occur in a default argument}} +) async { + defer { + _ = __await getInt() // expected-error{{'async' call cannot occur in a defer body}} + } + print("foo") +} + +func test3() { // expected-note{{add 'async' to function 'test3()' to make it asynchronous}} + _ = __await getInt() // expected-error{{'async' in a function that does not support concurrency}} +} + +enum SomeEnum: Int { +case foo = __await 5 // expected-error{{raw value for enum case must be a literal}} +} + +struct SomeStruct { + var x = __await getInt() // expected-error{{'async' call cannot occur in a property initializer}} + static var y = __await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}} +} + +func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) { } +func acceptAutoclosureAsync(_: @autoclosure () async -> Int) { } + +func testAutoclosure() async { + acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} + acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + + acceptAutoclosureAsync(__await getInt()) + acceptAutoclosureNonAsync(__await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + + __await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} + // expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}} + __await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + // expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}} +} From 4391f4264ecaa17365a0823562d157eabece7b1b Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Tue, 11 Aug 2020 09:14:12 -0700 Subject: [PATCH 072/663] [AutoDiff] Fix `Optional` differentiation crash. (#33386) Fix `Optional` differentiation crash for non-resilient `Wrapped` reference type. Add `NonresilientTracked` type to `DifferentiationUnittest` for testing. Resolves SR-13377. --- .../Differentiation/PullbackCloner.cpp | 13 +- .../DifferentiationUnittest/CMakeLists.txt | 2 +- ...wift => DifferentiationUnittest.swift.gyb} | 206 +++++++----- test/AutoDiff/validation-test/optional.swift | 295 +++++++++++++++--- 4 files changed, 387 insertions(+), 129 deletions(-) rename stdlib/private/DifferentiationUnittest/{DifferentiationUnittest.swift => DifferentiationUnittest.swift.gyb} (50%) diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 79611c38eaaf4..aa40f16f53d91 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -2056,8 +2056,8 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( // Find `Optional.some` EnumElementDecl. auto someEltDecl = builder.getASTContext().getOptionalSomeDecl(); - // Initialize a `Optional` buffer from `wrappedAdjoint`as the - // input for `Optional.TangentVector.init`. + // Initialize an `Optional` buffer from `wrappedAdjoint` as + // the input for `Optional.TangentVector.init`. auto *optArgBuf = builder.createAllocStack(pbLoc, optionalOfWrappedTanType); if (optionalOfWrappedTanType.isLoadableOrOpaque(builder.getFunction())) { // %enum = enum $Optional, #Optional.some!enumelt, @@ -2066,7 +2066,7 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( optionalOfWrappedTanType); // store %enum to %optArgBuf builder.emitStoreValueOperation(pbLoc, enumInst, optArgBuf, - StoreOwnershipQualifier::Trivial); + StoreOwnershipQualifier::Init); } else { // %enumAddr = init_enum_data_addr %optArgBuf $Optional, // #Optional.some!enumelt @@ -2279,14 +2279,15 @@ void PullbackCloner::Implementation::visitSILBasicBlock(SILBasicBlock *bb) { for (auto pair : incomingValues) { auto *predBB = std::get<0>(pair); auto incomingValue = std::get<1>(pair); - blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); // Handle `switch_enum` on `Optional`. auto termInst = bbArg->getSingleTerminator(); - if (isSwitchEnumInstOnOptional(termInst)) + if (isSwitchEnumInstOnOptional(termInst)) { accumulateAdjointForOptional(bb, incomingValue, concreteBBArgAdjCopy); - else + } else { + blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); setAdjointValue(predBB, incomingValue, makeConcreteAdjointValue(concreteBBArgAdjCopy)); + } } break; } diff --git a/stdlib/private/DifferentiationUnittest/CMakeLists.txt b/stdlib/private/DifferentiationUnittest/CMakeLists.txt index bb6284b191310..33da12b9b766a 100644 --- a/stdlib/private/DifferentiationUnittest/CMakeLists.txt +++ b/stdlib/private/DifferentiationUnittest/CMakeLists.txt @@ -1,6 +1,6 @@ add_swift_target_library(swiftDifferentiationUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB # This file should be listed first. Module name is inferred from the filename. - DifferentiationUnittest.swift + GYB_SOURCES DifferentiationUnittest.swift.gyb SWIFT_MODULE_DEPENDS _Differentiation StdlibUnittest INSTALL_IN_COMPONENT stdlib-experimental diff --git a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb similarity index 50% rename from stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift rename to stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb index f24dd18a7925e..282f89f93324f 100644 --- a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift +++ b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb @@ -1,4 +1,4 @@ -//===--- DifferentiationUnittest.swift ------------------------------------===// +//===--- DifferentiationUnittest.swift.gyb --------------------------------===// // // This source file is part of the Swift.org open source project // @@ -43,19 +43,21 @@ public extension TestSuite { _ testFunction: @escaping () -> Void ) { test(name, file: file, line: line) { - withLeakChecking(expectedLeakCount: expectedLeakCount, file: file, - line: line, testFunction) + withLeakChecking( + expectedLeakCount: expectedLeakCount, file: file, + line: line, testFunction) } } } -/// A type that tracks the number of live instances of a wrapped value type. +/// A resilient type that tracks the number of live instances of a wrapped +/// value type. /// /// `Tracked` is used to check for memory leaks in functions created via /// automatic differentiation. public struct Tracked { - fileprivate class Box { - fileprivate var value : T + internal class Box { + fileprivate var value: T init(_ value: T) { self.value = value _GlobalLeakCount.count += 1 @@ -64,71 +66,109 @@ public struct Tracked { _GlobalLeakCount.count -= 1 } } - private var handle: Box + internal var handle: Box - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public init(_ value: T) { self.handle = Box(value) } - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public var value: T { get { handle.value } set { handle.value = newValue } } } -extension Tracked : ExpressibleByFloatLiteral where T : ExpressibleByFloatLiteral { +/// A non-resilient type that tracks the number of live instances of a wrapped +/// value type. +/// +/// `NonresilientTracked` is used to check for memory leaks in functions +/// created via automatic differentiation. +@frozen +public struct NonresilientTracked { + @usableFromInline + internal class Box { + fileprivate var value: T + init(_ value: T) { + self.value = value + _GlobalLeakCount.count += 1 + } + deinit { + _GlobalLeakCount.count -= 1 + } + } + @usableFromInline + internal var handle: Box + + @differentiable(where T: Differentiable, T == T.TangentVector) + public init(_ value: T) { + self.handle = Box(value) + } + + @differentiable(where T: Differentiable, T == T.TangentVector) + public var value: T { + get { handle.value } + set { handle.value = newValue } + } +} + +% for Self in ['Tracked', 'NonresilientTracked']: + +extension ${Self}: ExpressibleByFloatLiteral +where T: ExpressibleByFloatLiteral { public init(floatLiteral value: T.FloatLiteralType) { self.handle = Box(T(floatLiteral: value)) } } -extension Tracked : CustomStringConvertible { - public var description: String { return "Tracked(\(value))" } +extension ${Self}: CustomStringConvertible { + public var description: String { return "${Self}(\(value))" } } -extension Tracked : ExpressibleByIntegerLiteral where T : ExpressibleByIntegerLiteral { +extension ${Self}: ExpressibleByIntegerLiteral +where T: ExpressibleByIntegerLiteral { public init(integerLiteral value: T.IntegerLiteralType) { self.handle = Box(T(integerLiteral: value)) } } -extension Tracked : Comparable where T : Comparable { - public static func < (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Comparable where T: Comparable { + public static func < (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value < rhs.value } - public static func <= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func <= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value <= rhs.value } - public static func > (lhs: Tracked, rhs: Tracked) -> Bool { + public static func > (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value > rhs.value } - public static func >= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func >= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value >= rhs.value } } -extension Tracked : AdditiveArithmetic where T : AdditiveArithmetic { - public static var zero: Tracked { return Tracked(T.zero) } - public static func + (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value + rhs.value) +extension ${Self}: AdditiveArithmetic where T: AdditiveArithmetic { + public static var zero: ${Self} { return ${Self}(T.zero) } + public static func + (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value + rhs.value) } - public static func - (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value - rhs.value) + public static func - (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value - rhs.value) } } -extension Tracked : Equatable where T : Equatable { - public static func == (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Equatable where T: Equatable { + public static func == (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value == rhs.value } } -extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magnitude { - public typealias Magnitude = Tracked +extension ${Self}: SignedNumeric & Numeric +where T: SignedNumeric, T == T.Magnitude { + public typealias Magnitude = ${Self} - public init?(exactly source: U) where U : BinaryInteger { + public init?(exactly source: U) where U: BinaryInteger { if let t = T(exactly: source) { self.init(t) } @@ -136,169 +176,191 @@ extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magn } public var magnitude: Magnitude { return Magnitude(value.magnitude) } - public static func * (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value * rhs.value) + public static func * (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value * rhs.value) } - public static func *= (lhs: inout Tracked, rhs: Tracked) { + public static func *= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs * rhs } } -extension Tracked where T : FloatingPoint { - public static func / (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value / rhs.value) +extension ${Self} where T: FloatingPoint { + public static func / (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value / rhs.value) } - public static func /= (lhs: inout Tracked, rhs: Tracked) { + public static func /= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs / rhs } } -extension Tracked : Strideable where T : Strideable, T.Stride == T.Stride.Magnitude { - public typealias Stride = Tracked +extension ${Self}: Strideable +where T: Strideable, T.Stride == T.Stride.Magnitude { + public typealias Stride = ${Self} - public func distance(to other: Tracked) -> Stride { + public func distance(to other: ${Self}) -> Stride { return Stride(value.distance(to: other.value)) } - public func advanced(by n: Stride) -> Tracked { - return Tracked(value.advanced(by: n.value)) + public func advanced(by n: Stride) -> ${Self} { + return ${Self}(value.advanced(by: n.value)) } } // For now, `T` must be restricted to trivial types (like `Float` or `Tensor`). -extension Tracked : Differentiable where T : Differentiable, T == T.TangentVector { - public typealias TangentVector = Tracked +extension ${Self}: Differentiable +where T: Differentiable, T == T.TangentVector { + public typealias TangentVector = ${Self} } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: init) internal static func _vjpInit(_ value: T) - -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) { - return (Tracked(value), { v in v.value }) + -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) + { + return (${Self}(value), { v in v.value }) } @usableFromInline @derivative(of: init) internal static func _jvpInit(_ value: T) - -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) { - return (Tracked(value), { v in Tracked(v) }) + -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) + { + return (${Self}(value), { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _vjpValue() -> (value: T, pullback: (T.TangentVector) -> Self.TangentVector) { - return (value, { v in Tracked(v) }) + internal func _vjpValue() -> ( + value: T, pullback: (T.TangentVector) -> Self.TangentVector + ) { + return (value, { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _jvpValue() -> (value: T, differential: (Self.TangentVector) -> T.TangentVector) { + internal func _jvpValue() -> ( + value: T, differential: (Self.TangentVector) -> T.TangentVector + ) { return (value, { v in v.value }) } } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: +) internal static func _vjpAdd(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs + rhs, { v in (v, v) }) } @usableFromInline @derivative(of: +) internal static func _jvpAdd(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs + rhs, { $0 + $1 }) } @usableFromInline @derivative(of: -) internal static func _vjpSubtract(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs - rhs, { v in (v, .zero - v) }) } @usableFromInline @derivative(of: -) internal static func _jvpSubtract(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs - rhs, { $0 - $1 }) } } -extension Tracked where T : Differentiable & SignedNumeric, T == T.Magnitude, - T == T.TangentVector { +extension ${Self} +where + T: Differentiable & SignedNumeric, T == T.Magnitude, + T == T.TangentVector +{ @usableFromInline @derivative(of: *) internal static func _vjpMultiply(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs * rhs, { v in (v * rhs, v * lhs) }) } @usableFromInline @derivative(of: *) internal static func _jvpMultiply(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs * rhs, { (dx, dy) in dx * rhs + dy * lhs }) } } -extension Tracked where T : Differentiable & FloatingPoint, T == T.TangentVector { +extension ${Self} +where T: Differentiable & FloatingPoint, T == T.TangentVector { @usableFromInline @derivative(of: /) internal static func _vjpDivide(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs / rhs, { v in (v / rhs, -lhs / (rhs * rhs) * v) }) } @usableFromInline @derivative(of: /) internal static func _jvpDivide(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs / rhs, { (dx, dy) in dx / rhs - lhs / (rhs * rhs) * dy }) } } -// Differential operators for `Tracked`. +// Differential operators for `${Self}`. public func gradient( - at x: T, in f: @differentiable (T) -> Tracked + at x: T, in f: @differentiable (T) -> ${Self} ) -> T.TangentVector where R.TangentVector == R { return pullback(at: x, in: f)(1) } public func gradient( - at x: T, _ y: U, in f: @differentiable (T, U) -> Tracked + at x: T, _ y: U, in f: @differentiable (T, U) -> ${Self} ) -> (T.TangentVector, U.TangentVector) where R.TangentVector == R { return pullback(at: x, y, in: f)(1) } public func derivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> R.TangentVector where T.TangentVector == T { return differential(at: x, in: f)(1) } public func derivative( - at x: Tracked, _ y: Tracked, - in f: @differentiable (Tracked, Tracked) -> R + at x: ${Self}, _ y: ${Self}, + in f: @differentiable (${Self}, ${Self}) -> R ) -> R.TangentVector where T.TangentVector == T, U.TangentVector == U { return differential(at: x, y, in: f)(1, 1) } public func valueWithGradient( - at x: T, in f: @differentiable (T) -> Tracked -) -> (value: Tracked, gradient: T.TangentVector) { + at x: T, in f: @differentiable (T) -> ${Self} +) -> (value: ${Self}, gradient: T.TangentVector) { let (y, pullback) = valueWithPullback(at: x, in: f) return (y, pullback(1)) } public func valueWithDerivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> (value: R, derivative: R.TangentVector) { let (y, differential) = valueWithDifferential(at: x, in: f) return (y, differential(1)) } + +% end diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift index c2fc0fac4a695..4aeb60ba42762 100644 --- a/test/AutoDiff/validation-test/optional.swift +++ b/test/AutoDiff/validation-test/optional.swift @@ -1,8 +1,8 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test -import StdlibUnittest import DifferentiationUnittest +import StdlibUnittest var OptionalTests = TestSuite("OptionalDifferentiation") @@ -23,7 +23,7 @@ OptionalTests.test("Let") { @differentiable func optional_let(_ maybeX: Float?) -> Float { if let x = maybeX { - return x * x + return x * x } return 10 } @@ -33,13 +33,27 @@ OptionalTests.test("Let") { @differentiable func optional_let_tracked(_ maybeX: Tracked?) -> Tracked { if let x = maybeX { - return x * x + return x * x } return 10 } expectEqual(gradient(at: 10, in: optional_let_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_let_tracked), .init(0.0)) + @differentiable + func optional_let_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_let_nonresilient_tracked), .init(0.0)) + @differentiable func optional_let_nested(_ nestedMaybeX: Float??) -> Float { if let maybeX = nestedMaybeX { @@ -54,7 +68,26 @@ OptionalTests.test("Let") { expectEqual(gradient(at: nil, in: optional_let_nested), .init(.init(0.0))) @differentiable - func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked< + Float + > { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_let_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { if let maybeX = nestedMaybeX { if let x = maybeX { return x * x @@ -63,24 +96,38 @@ OptionalTests.test("Let") { } return 10 } - expectEqual(gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_let_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_let_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_let_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { if let x = maybeX { - return x + return x } return defaultValue } expectEqual(gradient(at: 10, 20, in: optional_let_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) - expectEqual(gradient(at: Tracked.init(10), Tracked.init(20), in: optional_let_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, Tracked.init(20), in: optional_let_generic), (.init(0.0), 1.0)) + expectEqual( + gradient( + at: Tracked.init(10), Tracked.init(20), + in: optional_let_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, Tracked.init(20), in: optional_let_generic), + (.init(0.0), 1.0)) @differentiable - func optional_let_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_let_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { if let maybeX = nestedMaybeX { if let x = maybeX { return x @@ -90,8 +137,12 @@ OptionalTests.test("Let") { return defaultValue } - expectEqual(gradient(at: 10.0, 20.0, in: optional_let_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_let_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10.0, 20.0, in: optional_let_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_nested_generic), + (.init(.init(0.0)), 1.0)) } OptionalTests.test("Switch") { @@ -115,14 +166,28 @@ OptionalTests.test("Switch") { expectEqual(gradient(at: 10, in: optional_switch_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_switch_tracked), .init(0.0)) + @differentiable + func optional_switch_nonresilient_tracked( + _ maybeX: NonresilientTracked? + ) -> NonresilientTracked { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_switch_nonresilient_tracked), .init(0.0)) + @differentiable func optional_switch_nested(_ nestedMaybeX: Float??) -> Float { switch nestedMaybeX { case nil: return 10 case let .some(maybeX): switch maybeX { - case nil: return 10 - case let .some(x): return x * x + case nil: return 10 + case let .some(x): return x * x } } } @@ -130,42 +195,76 @@ OptionalTests.test("Switch") { expectEqual(gradient(at: nil, in: optional_switch_nested), .init(.init(0.0))) @differentiable - func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { switch nestedMaybeX { case nil: return 10 case let .some(maybeX): switch maybeX { - case nil: return 10 - case let .some(x): return x * x + case nil: return 10 + case let .some(x): return x * x } } } - expectEqual(gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) @differentiable - func optional_switch_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_switch_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_switch_generic( + _ maybeX: T?, _ defaultValue: T + ) -> T { switch maybeX { case nil: return defaultValue case let .some(x): return x } } - expectEqual(gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) @differentiable - func optional_switch_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_switch_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { switch nestedMaybeX { case nil: return defaultValue case let .some(maybeX): switch maybeX { - case nil: return defaultValue - case let .some(x): return x + case nil: return defaultValue + case let .some(x): return x } } } - expectEqual(gradient(at: 10, 20, in: optional_switch_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_switch_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_switch_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_nested_generic), + (.init(.init(0.0)), 1.0)) } OptionalTests.test("Var1") { @@ -173,7 +272,7 @@ OptionalTests.test("Var1") { func optional_var1(_ maybeX: Float?) -> Float { var maybeX = maybeX if let x = maybeX { - return x * x + return x * x } return 10 } @@ -184,13 +283,28 @@ OptionalTests.test("Var1") { func optional_var1_tracked(_ maybeX: Tracked?) -> Tracked { var maybeX = maybeX if let x = maybeX { - return x * x + return x * x } return 10 } expectEqual(gradient(at: 10, in: optional_var1_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_var1_tracked), .init(0.0)) + @differentiable + func optional_var1_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var1_nonresilient_tracked), .init(0.0)) + @differentiable func optional_var1_nested(_ nestedMaybeX: Float??) -> Float { var nestedMaybeX = nestedMaybeX @@ -206,7 +320,9 @@ OptionalTests.test("Var1") { expectEqual(gradient(at: nil, in: optional_var1_nested), .init(.init(0.0))) @differentiable - func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { var nestedMaybeX = nestedMaybeX if let maybeX = nestedMaybeX { if var x = maybeX { @@ -216,22 +332,50 @@ OptionalTests.test("Var1") { } return 10 } - expectEqual(gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) @differentiable - func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_var1_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { var maybeX = maybeX if let x = maybeX { - return x + return x } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) @differentiable - func optional_var1_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_var1_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { var nestedMaybeX = nestedMaybeX if let maybeX = nestedMaybeX { if var x = maybeX { @@ -241,8 +385,12 @@ OptionalTests.test("Var1") { } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var1_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var1_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var1_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_nested_generic), + (.init(.init(0.0)), 1.0)) } OptionalTests.test("Var2") { @@ -266,6 +414,20 @@ OptionalTests.test("Var2") { expectEqual(gradient(at: 10, in: optional_var2_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_var2_tracked), .init(0.0)) + @differentiable + func optional_var2_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var2_nonresilient_tracked), .init(0.0)) + @differentiable func optional_var2_nested(_ nestedMaybeX: Float??) -> Float { if var maybeX = nestedMaybeX { @@ -280,7 +442,26 @@ OptionalTests.test("Var2") { expectEqual(gradient(at: nil, in: optional_var2_nested), .init(.init(0.0))) @differentiable - func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var2_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { if var maybeX = nestedMaybeX { if var x = maybeX { return x * x @@ -289,21 +470,31 @@ OptionalTests.test("Var2") { } return 10 } - expectEqual(gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_var2_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { if var x = maybeX { return x } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) @differentiable - func optional_var2_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_var2_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { if var maybeX = nestedMaybeX { if var x = maybeX { return x @@ -312,8 +503,12 @@ OptionalTests.test("Var2") { } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var2_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var2_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var2_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_nested_generic), + (.init(.init(0.0)), 1.0)) } runAllTests() From 89c499ec61a613644d3f57336f54212a917b5bc3 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 11 Aug 2020 09:35:45 -0700 Subject: [PATCH 073/663] [ConstraintSystem] Remove default argument for updateWorkList from ConstraintSystem::mergeEquivalenceClasses. Most callers don't use the default, and it's important to consider the value of this argument for each call to mergeEquivalenceClasses. --- lib/Sema/CSSimplify.cpp | 4 ++-- lib/Sema/ConstraintSystem.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 6468c1e5a0cc1..1e9e1e969596f 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4529,7 +4529,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, return formUnsolvedResult(); // Merge the equivalence classes corresponding to these two variables. - mergeEquivalenceClasses(rep1, rep2); + mergeEquivalenceClasses(rep1, rep2, /*updateWorkList=*/true); return getTypeMatchSuccess(); } @@ -4581,7 +4581,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, if (!rep1->getImpl().canBindToInOut() || !rep2->getImpl().canBindToLValue()) { // Merge the equivalence classes corresponding to these two variables. - mergeEquivalenceClasses(rep1, rep2); + mergeEquivalenceClasses(rep1, rep2, /*updateWorkList=*/true); return getTypeMatchSuccess(); } } diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 2f3c275b32d5e..1b8331deaa30a 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3443,7 +3443,7 @@ class ConstraintSystem { /// distinct. void mergeEquivalenceClasses(TypeVariableType *typeVar1, TypeVariableType *typeVar2, - bool updateWorkList = true); + bool updateWorkList); /// Flags that direct type matching. enum TypeMatchFlags { From a8255f2601cb772131c0b3b3db43929194037e48 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 11 Aug 2020 10:40:56 -0700 Subject: [PATCH 074/663] abi-checker: allow ABI checker to deserialize @_implementationOnly modules on demand This could prevent the tool from crashing when module recovery failed. --- tools/swift-api-digester/swift-api-digester.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index 6e69d0cf36eb8..2b089bf718c5f 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -2548,6 +2548,8 @@ static int prepareForDump(const char *Main, InitInvok.getLangOptions().Target.isOSDarwin(); InitInvok.getClangImporterOptions().ModuleCachePath = options::ModuleCachePath; + // Module recovery issue shouldn't bring down the tool. + InitInvok.getLangOptions().AllowDeserializingImplementationOnly = true; if (!options::SwiftVersion.empty()) { using version::Version; From 54d25818867e07594a027546f2f9d65827a66423 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 11 Aug 2020 12:10:30 -0700 Subject: [PATCH 075/663] [ConstraintSystem] Add `isStaticallyDerivedMetatype` to `Solution` This is useful for a new style code completion which doesn't apply solutions back to neither constraint system nor AST. --- lib/Sema/CSApply.cpp | 34 ++++++++++++++++++++++++++++++++++ lib/Sema/ConstraintSystem.h | 10 ++++++++++ 2 files changed, 44 insertions(+) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c5715942de0c6..e5b59b4ff06de 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -176,12 +176,46 @@ bool ConstraintSystem::isTypeReference(Expr *E) { }); } +bool Solution::isTypeReference(Expr *E) const { + return E->isTypeReference( + [&](Expr *expr) -> Type { return simplifyType(getType(expr)); }, + [&](Expr *expr) -> Decl * { + ConstraintLocator *locator = nullptr; + if (auto *UDE = dyn_cast(E)) { + locator = getConstraintLocator(UDE, {ConstraintLocator::Member}); + } + + if (auto *UME = dyn_cast(E)) { + locator = + getConstraintLocator(UME, {ConstraintLocator::UnresolvedMember}); + } + + if (isa(E)) + locator = getConstraintLocator(const_cast(E)); + + if (locator) { + if (auto selectedOverload = getOverloadChoiceIfAvailable(locator)) { + const auto &choice = selectedOverload->choice; + return choice.getDeclOrNull(); + } + } + + return nullptr; + }); +} + bool ConstraintSystem::isStaticallyDerivedMetatype(Expr *E) { return E->isStaticallyDerivedMetatype( [&](Expr *E) -> Type { return simplifyType(getType(E)); }, [&](Expr *E) -> bool { return isTypeReference(E); }); } +bool Solution::isStaticallyDerivedMetatype(Expr *E) const { + return E->isStaticallyDerivedMetatype( + [&](Expr *E) -> Type { return simplifyType(getType(E)); }, + [&](Expr *E) -> bool { return isTypeReference(E); }); +} + Type ConstraintSystem::getInstanceType(TypeExpr *E) { if (!hasType(E)) return Type(); diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 4e4924a0bc78b..9059b98fdb494 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1210,6 +1210,16 @@ class Solution { : nullptr; } + /// This method implements functionality of `Expr::isTypeReference` + /// with data provided by a given solution. + bool isTypeReference(Expr *E) const; + + /// Call Expr::isIsStaticallyDerivedMetatype on the given + /// expression, using a custom accessor for the type on the + /// expression that reads the type from the Solution + /// expression type map. + bool isStaticallyDerivedMetatype(Expr *E) const; + SWIFT_DEBUG_DUMP; /// Dump this solution. From a81b7d19e8f7591e098c7f94deb34e88dd08d8f6 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 11 Aug 2020 12:14:09 -0700 Subject: [PATCH 076/663] [CSSolver] `solveForCodeCompletion` should fail if constraint generation fails --- lib/Sema/CSSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 7af6590a65c0d..40e890e804525 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1428,7 +1428,7 @@ void ConstraintSystem::solveForCodeCompletion( cs.shrink(expr); - if (cs.generateConstraints(expr, DC)) + if (!cs.generateConstraints(expr, DC)) return; llvm::SmallVector solutions; From 73262ae2a974bc23e670204f49eae16e20859aec Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 11 Aug 2020 12:19:21 -0700 Subject: [PATCH 077/663] [ConstraintSystem] Add `Solution::getResolvedType` to get a concrete type for a given `ASTNode` --- lib/Sema/CSApply.cpp | 4 ++++ lib/Sema/ConstraintSystem.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index e5b59b4ff06de..7a48a870a5d76 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -8415,6 +8415,10 @@ Type Solution::getType(ASTNode node) const { return cs.getType(node); } +Type Solution::getResolvedType(ASTNode node) const { + return simplifyType(getType(node)); +} + void Solution::setExprTypes(Expr *expr) const { if (!expr) return; diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 9059b98fdb494..b6b9fda6c1ae9 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1190,6 +1190,11 @@ class Solution { /// Retrieve the type of the given node, as recorded in this solution. Type getType(ASTNode node) const; + /// Retrieve the type of the given node as recorded in this solution + /// and resolve all of the type variables in contains to form a fully + /// "resolved" concrete type. + Type getResolvedType(ASTNode node) const; + /// Resolve type variables present in the raw type, using generic parameter /// types where possible. Type resolveInterfaceType(Type type) const; From a5dfae23805be2061a90dbb941c3abd37ffdf96e Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Mon, 10 Aug 2020 13:42:11 -0700 Subject: [PATCH 078/663] Update test IRGen/pic.swift for changed code generation rdar://66790508 --- test/IRGen/pic.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/IRGen/pic.swift b/test/IRGen/pic.swift index 6f7b9a8eaf1c3..def763b6bb0b1 100644 --- a/test/IRGen/pic.swift +++ b/test/IRGen/pic.swift @@ -62,10 +62,13 @@ public func use_global() -> Int { // armv7k: ldr [[R_ADR]], {{\[}}[[R_ADR]]{{\]}} // arm64-LABEL: {{_?}}$s4main10use_globalSiyF: +// arm64: adrp [[REG3:x[0-9]+]], _$s4main6globalSivp@PAGE // arm64: adrp [[REG1:x[0-9]+]], _$s4main6globalSivp@PAGE // arm64: add [[REG1]], [[REG1]], _$s4main6globalSivp@PAGEOFF +// arm64: str [[REG3]], [sp, #16] // arm64: bl _swift_beginAccess -// arm64: ldr [[REG2:x[0-9]+]], {{\[}}[[REG1]]{{\]}} +// arm64: ldr [[REG4:x[0-9]+]], [sp, #16] +// arm64: ldr [[REG2:x[0-9]+]], {{\[}}[[REG4]], _$s4main6globalSivp@PAGEOFF // arm64: str [[REG2]], [sp] // arm64: bl _swift_endAccess // arm64: ldr x0, [sp] From a4bea90c91abfbe846783741b6dc9db2f2980d74 Mon Sep 17 00:00:00 2001 From: Eric Miotto <1094986+edymtt@users.noreply.github.com> Date: Tue, 11 Aug 2020 13:12:04 -0700 Subject: [PATCH 079/663] [build] invoke swift-serialize-diagnostics for host architecture As a result of #33346 we are relying on the tool for the current target -- this will work for the host architecture but will fail when crosscompiling. Addresses rdar://66800239 --- localization/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index 764b378f97b44..6a4ac7b0351fa 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -4,12 +4,13 @@ add_custom_command(TARGET diagnostic-database COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/ ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ COMMAND - $ + "${SWIFT_NATIVE_SWIFT_TOOLS_PATH}/swift-serialize-diagnostics" --input-file-path ${CMAKE_BINARY_DIR}/share/swift/diagnostics/en.yaml --output-directory ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ ) add_dependencies(swift-frontend diagnostic-database) +add_dependencies(diagnostic-database swift-serialize-diagnostics) swift_install_in_component( DIRECTORY ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ From 5dd1bfea8d9dbb16c71d5427dd5440273828b50b Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 11 Aug 2020 13:59:59 -0700 Subject: [PATCH 080/663] [Concurrency] Add support for 'async' closures. Closurea can become 'async' in one of two ways: * They can be explicitly marked 'async' prior to the 'in' * They can be inferred as 'async' if they include 'await' in the body --- include/swift/AST/Expr.h | 17 +++- include/swift/AST/ExtInfo.h | 8 ++ include/swift/Parse/Parser.h | 1 + lib/Parse/ParseExpr.cpp | 51 ++++++++---- lib/Sema/CSGen.cpp | 77 +++++++++++++++---- lib/Sema/DebuggerTestingTransform.cpp | 4 +- lib/Sema/DerivedConformanceDifferentiable.cpp | 10 +-- test/Parse/async-syntax.swift | 6 ++ test/expr/unary/async_await.swift | 16 ++++ utils/gyb_syntax_support/ExprNodes.py | 3 + 10 files changed, 150 insertions(+), 43 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index a75d9d56b39e4..0e6e4070b158b 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -3815,6 +3815,9 @@ class ClosureExpr : public AbstractClosureExpr { /// this information directly on the ClosureExpr. VarDecl * CapturedSelfDecl; + /// The location of the "async", if present. + SourceLoc AsyncLoc; + /// The location of the "throws", if present. SourceLoc ThrowsLoc; @@ -3833,14 +3836,15 @@ class ClosureExpr : public AbstractClosureExpr { llvm::PointerIntPair Body; public: ClosureExpr(SourceRange bracketRange, VarDecl *capturedSelfDecl, - ParameterList *params, SourceLoc throwsLoc, SourceLoc arrowLoc, - SourceLoc inLoc, TypeExpr *explicitResultType, + ParameterList *params, SourceLoc asyncLoc, SourceLoc throwsLoc, + SourceLoc arrowLoc, SourceLoc inLoc, TypeExpr *explicitResultType, unsigned discriminator, DeclContext *parent) : AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false, discriminator, parent), BracketRange(bracketRange), CapturedSelfDecl(capturedSelfDecl), - ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc), + AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), + InLoc(inLoc), ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed), Body(nullptr) { setParameterList(params); @@ -3888,7 +3892,12 @@ class ClosureExpr : public AbstractClosureExpr { SourceLoc getInLoc() const { return InLoc; } - + + /// Retrieve the location of the 'async' for a closure that has it. + SourceLoc getAsyncLoc() const { + return AsyncLoc; + } + /// Retrieve the location of the 'throws' for a closure that has it. SourceLoc getThrowsLoc() const { return ThrowsLoc; diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 639b982d25e73..a19023f621042 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -436,6 +436,14 @@ class ASTExtInfo { return builder.withThrows(throws).build(); } + /// Helper method for changing only the async field. + /// + /// Prefer using \c ASTExtInfoBuilder::withAsync for chaining. + LLVM_NODISCARD + ASTExtInfo withAsync(bool async = true) const { + return builder.withAsync(async).build(); + } + bool isEqualTo(ASTExtInfo other, bool useClangTypes) const { return builder.isEqualTo(other.builder, useClangTypes); } diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 625092e4a3ba3..2d2119941cd51 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1572,6 +1572,7 @@ class Parser { SmallVectorImpl &captureList, VarDecl *&capturedSelfParamDecl, ParameterList *¶ms, + SourceLoc &asyncLoc, SourceLoc &throwsLoc, SourceLoc &arrowLoc, TypeExpr *&explicitResultType, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d7f77869d6723..a22f077316840 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2432,7 +2432,8 @@ bool Parser:: parseClosureSignatureIfPresent(SourceRange &bracketRange, SmallVectorImpl &captureList, VarDecl *&capturedSelfDecl, - ParameterList *¶ms, SourceLoc &throwsLoc, + ParameterList *¶ms, + SourceLoc &asyncLoc, SourceLoc &throwsLoc, SourceLoc &arrowLoc, TypeExpr *&explicitResultType, SourceLoc &inLoc){ // Clear out result parameters. @@ -2444,6 +2445,24 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, explicitResultType = nullptr; inLoc = SourceLoc(); + // Consume 'async', 'throws', and 'rethrows', but in any order. + auto consumeAsyncThrows = [&] { + bool hadAsync = false; + if (Context.LangOpts.EnableExperimentalConcurrency && + Tok.isContextualKeyword("async")) { + consumeToken(); + hadAsync = true; + } + + if (!consumeIf(tok::kw_throws) && !consumeIf(tok::kw_rethrows)) + return; + + if (Context.LangOpts.EnableExperimentalConcurrency && !hadAsync && + Tok.isContextualKeyword("async")) { + consumeToken(); + } + }; + // If we have a leading token that may be part of the closure signature, do a // speculative parse to validate it and look for 'in'. if (Tok.isAny(tok::l_paren, tok::l_square, tok::identifier, tok::kw__)) { @@ -2465,7 +2484,8 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, // Consume the ')', if it's there. if (consumeIf(tok::r_paren)) { - consumeIf(tok::kw_throws) || consumeIf(tok::kw_rethrows); + consumeAsyncThrows(); + // Parse the func-signature-result, if present. if (consumeIf(tok::arrow)) { if (!canParseType()) @@ -2485,8 +2505,8 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, return false; } - - consumeIf(tok::kw_throws) || consumeIf(tok::kw_rethrows); + + consumeAsyncThrows(); // Parse the func-signature-result, if present. if (consumeIf(tok::arrow)) { @@ -2682,11 +2702,10 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, params = ParameterList::create(Context, elements); } - - if (Tok.is(tok::kw_throws)) { - throwsLoc = consumeToken(); - } else if (Tok.is(tok::kw_rethrows)) { - throwsLoc = consumeToken(); + + bool rethrows = false; + parseAsyncThrows(SourceLoc(), asyncLoc, throwsLoc, &rethrows); + if (rethrows) { diagnose(throwsLoc, diag::rethrowing_function_type) .fixItReplace(throwsLoc, "throws"); } @@ -2803,13 +2822,14 @@ ParserResult Parser::parseExprClosure() { SmallVector captureList; VarDecl *capturedSelfDecl; ParameterList *params = nullptr; + SourceLoc asyncLoc; SourceLoc throwsLoc; SourceLoc arrowLoc; TypeExpr *explicitResultType; SourceLoc inLoc; - parseClosureSignatureIfPresent(bracketRange, captureList, - capturedSelfDecl, params, throwsLoc, - arrowLoc, explicitResultType, inLoc); + parseClosureSignatureIfPresent( + bracketRange, captureList, capturedSelfDecl, params, asyncLoc, throwsLoc, + arrowLoc, explicitResultType, inLoc); // If the closure was created in the context of an array type signature's // size expression, there will not be a local context. A parse error will @@ -2824,10 +2844,9 @@ ParserResult Parser::parseExprClosure() { unsigned discriminator = CurLocalContext->claimNextClosureDiscriminator(); // Create the closure expression and enter its context. - auto *closure = new (Context) ClosureExpr(bracketRange, capturedSelfDecl, - params, throwsLoc, arrowLoc, inLoc, - explicitResultType, discriminator, - CurDeclContext); + auto *closure = new (Context) ClosureExpr( + bracketRange, capturedSelfDecl, params, asyncLoc, throwsLoc, arrowLoc, + inLoc, explicitResultType, discriminator, CurDeclContext); // The arguments to the func are defined in their own scope. Scope S(this, ScopeKind::ClosureParams); ParseFunctionBody cc(*this, closure); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index b4f0c1facc721..32df0c71e0633 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2114,9 +2114,7 @@ namespace { } } - auto extInfo = FunctionType::ExtInfo(); - if (closureCanThrow(closure)) - extInfo = extInfo.withThrows(); + auto extInfo = closureEffects(closure); // Closure expressions always have function type. In cases where a // parameter or return type is omitted, a fresh type variable is used to @@ -2596,9 +2594,12 @@ namespace { return CS.getType(expr->getClosureBody()); } - /// Walk a closure AST to determine if it can throw. - bool closureCanThrow(ClosureExpr *expr) { - // A walker that looks for 'try' or 'throw' expressions + /// Walk a closure AST to determine its effects. + /// + /// \returns a function's extended info describing the effects, as + /// determined syntactically. + FunctionType::ExtInfo closureEffects(ClosureExpr *expr) { + // A walker that looks for 'try' and 'throw' expressions // that aren't nested within closures, nested declarations, // or exhaustive catches. class FindInnerThrows : public ASTWalker { @@ -2743,18 +2744,62 @@ namespace { bool foundThrow() { return FoundThrow; } }; - - if (expr->getThrowsLoc().isValid()) - return true; - + + // A walker that looks for 'async' and 'await' expressions + // that aren't nested within closures or nested declarations. + class FindInnerAsync : public ASTWalker { + bool FoundAsync = false; + + std::pair walkToExprPre(Expr *expr) override { + // If we've found an 'await', record it and terminate the traversal. + if (isa(expr)) { + FoundAsync = true; + return { false, nullptr }; + } + + // Do not recurse into other closures. + if (isa(expr)) + return { false, expr }; + + return { true, expr }; + } + + bool walkToDeclPre(Decl *decl) override { + // Do not walk into function or type declarations. + if (!isa(decl)) + return false; + + return true; + } + + public: + bool foundAsync() { return FoundAsync; } + }; + + // If either 'throws' or 'async' was explicitly specified, use that + // set of effects. + bool throws = expr->getThrowsLoc().isValid(); + bool async = expr->getAsyncLoc().isValid(); + if (throws || async) { + return ASTExtInfoBuilder() + .withThrows(throws) + .withAsync(async) + .build(); + } + + // Scan the body to determine the effects. auto body = expr->getBody(); - if (!body) - return false; - - auto tryFinder = FindInnerThrows(CS, expr); - body->walk(tryFinder); - return tryFinder.foundThrow(); + return FunctionType::ExtInfo(); + + auto throwFinder = FindInnerThrows(CS, expr); + body->walk(throwFinder); + auto asyncFinder = FindInnerAsync(); + body->walk(asyncFinder); + return ASTExtInfoBuilder() + .withThrows(throwFinder.foundThrow()) + .withAsync(asyncFinder.foundAsync()) + .build(); } Type visitClosureExpr(ClosureExpr *closure) { diff --git a/lib/Sema/DebuggerTestingTransform.cpp b/lib/Sema/DebuggerTestingTransform.cpp index 082c9b6190b52..61484a57a0d77 100644 --- a/lib/Sema/DebuggerTestingTransform.cpp +++ b/lib/Sema/DebuggerTestingTransform.cpp @@ -227,8 +227,8 @@ class DebuggerTestingTransform : public ASTWalker { auto *Params = ParameterList::createEmpty(Ctx); auto *Closure = new (Ctx) ClosureExpr(SourceRange(), nullptr, Params, SourceLoc(), SourceLoc(), - SourceLoc(), nullptr, DF.getNextDiscriminator(), - getCurrentDeclContext()); + SourceLoc(), SourceLoc(), nullptr, + DF.getNextDiscriminator(), getCurrentDeclContext()); Closure->setImplicit(true); // TODO: Save and return the value of $OriginalExpr. diff --git a/lib/Sema/DerivedConformanceDifferentiable.cpp b/lib/Sema/DerivedConformanceDifferentiable.cpp index b479372be9da0..3f7e82700574a 100644 --- a/lib/Sema/DerivedConformanceDifferentiable.cpp +++ b/lib/Sema/DerivedConformanceDifferentiable.cpp @@ -393,9 +393,9 @@ deriveBodyDifferentiable_zeroTangentVectorInitializer( auto *closureParams = ParameterList::createEmpty(C); auto *closure = new (C) ClosureExpr( - SourceRange(), /*capturedSelfDecl*/ nullptr, closureParams, SourceLoc(), - SourceLoc(), SourceLoc(), TypeExpr::createImplicit(resultTy, C), - discriminator, funcDecl); + SourceRange(), /*capturedSelfDecl*/ nullptr, closureParams, + SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc(), + TypeExpr::createImplicit(resultTy, C), discriminator, funcDecl); closure->setImplicit(); auto *closureReturn = new (C) ReturnStmt(SourceLoc(), zeroExpr, true); auto *closureBody = @@ -504,8 +504,8 @@ deriveBodyDifferentiable_zeroTangentVectorInitializer( auto *closureParams = ParameterList::createEmpty(C); auto *closure = new (C) ClosureExpr( SourceRange(), /*capturedSelfDecl*/ nullptr, closureParams, SourceLoc(), - SourceLoc(), SourceLoc(), TypeExpr::createImplicit(resultTy, C), - discriminator, funcDecl); + SourceLoc(), SourceLoc(), SourceLoc(), + TypeExpr::createImplicit(resultTy, C), discriminator, funcDecl); closure->setImplicit(); auto *closureReturn = new (C) ReturnStmt(SourceLoc(), callExpr, true); auto *closureBody = diff --git a/test/Parse/async-syntax.swift b/test/Parse/async-syntax.swift index 54c1bac839969..4f91754b26f3f 100644 --- a/test/Parse/async-syntax.swift +++ b/test/Parse/async-syntax.swift @@ -14,3 +14,9 @@ func testTypeExprs() { func testAwaitOperator() async { let _ = __await asyncGlobal1() } + +func testAsyncClosure() { + let _ = { () async in 5 } + let _ = { () throws in 5 } + let _ = { () async throws in 5 } +} diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index e3de627591095..c7c7c89894766 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -48,3 +48,19 @@ func testAutoclosure() async { __await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} // expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}} } + +// Test inference of 'async' from the body of a closure. +func testClosure() { + let closure = { + __await getInt() + } + + let _: () -> Int = closure // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} + + let closure2 = { () async -> Int in + print("here") + return __await getInt() + } + + let _: () -> Int = closure2 // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} +} diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py index 8b442d8c307a1..7f26bce1de463 100644 --- a/utils/gyb_syntax_support/ExprNodes.py +++ b/utils/gyb_syntax_support/ExprNodes.py @@ -390,6 +390,9 @@ Child('SimpleInput', kind='ClosureParamList'), Child('Input', kind='ParameterClause'), ]), + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', + text_choices=['async'], is_optional=True), Child('ThrowsTok', kind='ThrowsToken', is_optional=True), Child('Output', kind='ReturnClause', is_optional=True), Child('InTok', kind='InToken'), From 3a3f92a2f7b0acbefecb9c26a72334067b96a004 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 11 Aug 2020 15:29:20 -0700 Subject: [PATCH 081/663] Implement Richer Diagnostics for Cross-File Synthesis Failures Mention the type, the requirement, and the extension in the error that follows. In editor mode, try to insert stubs for the missing requirement as well so the user isn't just left with a pile of unactionable errors. --- include/swift/AST/DiagnosticsSema.def | 5 +++-- lib/Sema/DerivedConformances.cpp | 20 ++++++++++++++++++ localization/diagnostics/en.yaml | 4 ++-- .../class_differentiable.swift | 6 ++++-- .../struct_additive_arithmetic.swift | 8 +++++-- .../struct_differentiable.swift | 6 ++++-- ...ixits-derived-conformances-multifile.swift | 6 ++++++ test/Sema/enum_conformance_synthesis.swift | 6 +++--- test/Sema/fixits-derived-conformances.swift | 21 +++++++++++++++++++ test/Sema/struct_equatable_hashable.swift | 4 ++-- 10 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 test/Sema/Inputs/fixits-derived-conformances-multifile.swift create mode 100644 test/Sema/fixits-derived-conformances.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ba013ef17706c..b343a4c445b26 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2765,8 +2765,9 @@ ERROR(cannot_synthesize_init_in_extension_of_nonfinal,none, "be satisfied by a 'required' initializer in the class definition", (Type, DeclName)) ERROR(cannot_synthesize_in_crossfile_extension,none, - "implementation of %0 cannot be automatically synthesized in an extension " - "in a different file to the type", (Type)) + "extension outside of file declaring %0 %1 prevents automatic synthesis " + "of %2 for protocol %3", + (DescriptiveDeclKind, DeclName, DeclName, Type)) ERROR(broken_additive_arithmetic_requirement,none, "AdditiveArithmetic protocol is broken: unexpected requirement", ()) diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 6b96232009592..b7204e4775e43 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "TypeChecker.h" +#include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/Stmt.h" #include "swift/AST/Expr.h" @@ -490,8 +491,27 @@ bool DerivedConformance::checkAndDiagnoseDisallowedContext( Nominal->getModuleScopeContext() != getConformanceContext()->getModuleScopeContext()) { ConformanceDecl->diagnose(diag::cannot_synthesize_in_crossfile_extension, + Nominal->getDescriptiveKind(), Nominal->getName(), + synthesizing->getName(), getProtocolType()); Nominal->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); + + // In editor mode, try to insert a stub. + if (Context.LangOpts.DiagnosticsEditorMode) { + auto Extension = cast(getConformanceContext()); + auto FixitLocation = Extension->getBraces().Start; + llvm::SmallString<128> Text; + { + llvm::raw_svector_ostream SS(Text); + swift::printRequirementStub(synthesizing, Nominal, + Nominal->getDeclaredType(), + Extension->getStartLoc(), SS); + if (!Text.empty()) { + ConformanceDecl->diagnose(diag::missing_witnesses_general) + .fixItInsertAfter(FixitLocation, Text.str()); + } + } + } return true; } diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index 8c3be67b2c0db..f61d7cdcbbfba 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -6556,8 +6556,8 @@ - id: cannot_synthesize_in_crossfile_extension msg: >- - implementation of %0 cannot be automatically synthesized in an extension - in a different file to the type + extension outside of file declaring %0 %1 prevents automatic synthesis + of %2 for protocol %3 - id: broken_additive_arithmetic_requirement msg: >- diff --git a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift index 4b1110b39636e..f4b50fb19fa21 100644 --- a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift +++ b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift @@ -570,8 +570,10 @@ class WrappedProperties: Differentiable { // Test derived conformances in disallowed contexts. -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension OtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring class 'OtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring class 'OtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension GenericOtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring generic class 'GenericOtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring generic class 'GenericOtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift b/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift index f6958318df05e..993be5409c16f 100644 --- a/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift +++ b/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift @@ -113,8 +113,12 @@ where T: AdditiveArithmetic {} // Test derived conformances in disallowed contexts. -// expected-error @+1 3 {{implementation of 'AdditiveArithmetic' cannot be automatically synthesized in an extension in a different file to the type}} extension OtherFileNonconforming: AdditiveArithmetic {} +// expected-error @-1 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of 'zero' for protocol 'AdditiveArithmetic'}} +// expected-error @-2 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of '+' for protocol 'AdditiveArithmetic'}} +// expected-error @-3 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of '-' for protocol 'AdditiveArithmetic'}} -// expected-error @+1 3 {{implementation of 'AdditiveArithmetic' cannot be automatically synthesized in an extension in a different file to the type}} extension GenericOtherFileNonconforming: AdditiveArithmetic {} +// expected-error @-1 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of 'zero' for protocol 'AdditiveArithmetic'}} +// expected-error @-2 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of '+' for protocol 'AdditiveArithmetic'}} +// expected-error @-3 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of '-' for protocol 'AdditiveArithmetic'}} diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift index 02f9154426cf4..e75b2730232f5 100644 --- a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift +++ b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift @@ -383,8 +383,10 @@ struct WrappedProperties: Differentiable { // Verify that cross-file derived conformances are disallowed. -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension OtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring struct 'OtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} -// expected-error @+1 2 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} extension GenericOtherFileNonconforming: Differentiable {} +// expected-error @-1 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of 'move(along:)' for protocol 'Differentiable'}} +// expected-error @-2 {{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of 'zeroTangentVectorInitializer' for protocol 'Differentiable'}} diff --git a/test/Sema/Inputs/fixits-derived-conformances-multifile.swift b/test/Sema/Inputs/fixits-derived-conformances-multifile.swift new file mode 100644 index 0000000000000..7512251332dbd --- /dev/null +++ b/test/Sema/Inputs/fixits-derived-conformances-multifile.swift @@ -0,0 +1,6 @@ +public enum Enum { case one } // expected-note {{type declared here}} +public enum GenericEnum { case one(Int) } // expected-note {{type declared here}} + +public struct Struct {} // expected-note {{type declared here}} +public struct GenericStruct {} // expected-note {{type declared here}} + diff --git a/test/Sema/enum_conformance_synthesis.swift b/test/Sema/enum_conformance_synthesis.swift index 494d1b3480b32..c486385669cda 100644 --- a/test/Sema/enum_conformance_synthesis.swift +++ b/test/Sema/enum_conformance_synthesis.swift @@ -224,7 +224,7 @@ enum Complex2 { } extension Complex2 : Hashable {} extension Complex2 : CaseIterable {} // expected-error {{type 'Complex2' does not conform to protocol 'CaseIterable'}} -extension FromOtherFile: CaseIterable {} // expected-error {{cannot be automatically synthesized in an extension in a different file to the type}} +extension FromOtherFile: CaseIterable {} // expected-error {{extension outside of file declaring enum 'FromOtherFile' prevents automatic synthesis of 'allCases' for protocol 'CaseIterable'}} extension CaseIterableAcrossFiles: CaseIterable { public static var allCases: [CaseIterableAcrossFiles] { return [ .A ] @@ -248,7 +248,7 @@ extension OtherFileNonconforming: Hashable { func hash(into hasher: inout Hasher) {} } // ...but synthesis in a type defined in another file doesn't work yet. -extension YetOtherFileNonconforming: Equatable {} // expected-error {{cannot be automatically synthesized in an extension in a different file to the type}} +extension YetOtherFileNonconforming: Equatable {} // expected-error {{extension outside of file declaring enum 'YetOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} extension YetOtherFileNonconforming: CaseIterable {} // expected-error {{does not conform}} // Verify that an indirect enum doesn't emit any errors as long as its "leaves" @@ -319,7 +319,7 @@ extension UnusedGenericDeriveExtension: Hashable {} // Cross-file synthesis is disallowed for conditional cases just as it is for // non-conditional ones. extension GenericOtherFileNonconforming: Equatable where T: Equatable {} -// expected-error@-1{{implementation of 'Equatable' cannot be automatically synthesized in an extension in a different file to the type}} +// expected-error@-1{{extension outside of file declaring generic enum 'GenericOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} // rdar://problem/41852654 diff --git a/test/Sema/fixits-derived-conformances.swift b/test/Sema/fixits-derived-conformances.swift new file mode 100644 index 0000000000000..7d63103ed135c --- /dev/null +++ b/test/Sema/fixits-derived-conformances.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name Types %S/Inputs/fixits-derived-conformances-multifile.swift -o %t/%target-library-name(Types) +// RUN: %swift -typecheck -target %target-triple -I %t -diagnostics-editor-mode -verify %s + +import Types + +extension GenericEnum: Equatable { } +// expected-error@-1 {{extension outside of file declaring generic enum 'GenericEnum' prevents automatic synthesis of '==' for protocol 'Equatable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{35-35=\n public static func == (lhs: GenericEnum, rhs: GenericEnum) -> Bool {\n <#code#>\n \}\n}} + +extension Struct: Equatable { } +// expected-error@-1 {{extension outside of file declaring struct 'Struct' prevents automatic synthesis of '==' for protocol 'Equatable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{30-30=\n public static func == (lhs: Struct, rhs: Struct) -> Bool {\n <#code#>\n \}\n}} +extension GenericStruct: Equatable { } +// expected-error@-1 {{extension outside of file declaring generic struct 'GenericStruct' prevents automatic synthesis of '==' for protocol 'Equatable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{37-37=\n public static func == (lhs: GenericStruct, rhs: GenericStruct) -> Bool {\n <#code#>\n \}\n}} + +extension Enum: CaseIterable { } +// expected-error@-1 {{extension outside of file declaring enum 'Enum' prevents automatic synthesis of 'allCases' for protocol 'CaseIterable'}} +// expected-note@-2 {{do you want to add protocol stubs?}}{{31-31=\n public static var allCases: [Enum]\n}} + diff --git a/test/Sema/struct_equatable_hashable.swift b/test/Sema/struct_equatable_hashable.swift index be162f1abd1a2..a25688d01d336 100644 --- a/test/Sema/struct_equatable_hashable.swift +++ b/test/Sema/struct_equatable_hashable.swift @@ -196,7 +196,7 @@ extension OtherFileNonconforming: Hashable { func hash(into hasher: inout Hasher) {} } // ...but synthesis in a type defined in another file doesn't work yet. -extension YetOtherFileNonconforming: Equatable {} // expected-error {{cannot be automatically synthesized in an extension in a different file to the type}} +extension YetOtherFileNonconforming: Equatable {} // expected-error {{extension outside of file declaring struct 'YetOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} // Verify that we can add Hashable conformance in an extension by only // implementing hash(into:) @@ -253,7 +253,7 @@ extension UnusedGenericDeriveExtension: Hashable {} // Cross-file synthesis is still disallowed for conditional cases extension GenericOtherFileNonconforming: Equatable where T: Equatable {} -// expected-error@-1{{implementation of 'Equatable' cannot be automatically synthesized in an extension in a different file to the type}} +// expected-error@-1{{extension outside of file declaring generic struct 'GenericOtherFileNonconforming' prevents automatic synthesis of '==' for protocol 'Equatable'}} // rdar://problem/41852654 From 01563cea97596be6740e85f4701bb02922174b30 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 11 Aug 2020 15:37:04 -0700 Subject: [PATCH 082/663] [NFC] Fold Switch-Nest in Obligation Verification Fold the switch statement to have each arm share as much code between them as possible. This reduces a ton of duplication from the error continuations and makes it slightly easier to update this code when more kinds of cases show up here later. --- lib/Frontend/DependencyVerifier.cpp | 85 +++++++++++------------------ 1 file changed, 32 insertions(+), 53 deletions(-) diff --git a/lib/Frontend/DependencyVerifier.cpp b/lib/Frontend/DependencyVerifier.cpp index b8950be51032d..2e468f83de842 100644 --- a/lib/Frontend/DependencyVerifier.cpp +++ b/lib/Frontend/DependencyVerifier.cpp @@ -481,71 +481,50 @@ bool DependencyVerifier::verifyObligations( auto &diags = SF->getASTContext().Diags; for (auto &expectation : ExpectedDependencies) { const bool wantsCascade = expectation.isCascading(); - switch (expectation.Info.Kind) { - case Expectation::Kind::Negative: + if (expectation.Info.Kind == Expectation::Kind::Negative) { // We'll verify negative expectations separately. NegativeExpectations.insert({expectation.MessageRange, expectation}); - break; - case Expectation::Kind::Member: - matchExpectationOrFail( - OM, expectation, - [&](Obligation &p) { - const auto haveCascade = p.getCascades(); + continue; + } + + matchExpectationOrFail( + OM, expectation, + [&](Obligation &O) { + const auto haveCascade = O.getCascades(); + switch (expectation.Info.Kind) { + case Expectation::Kind::Negative: + llvm_unreachable("Should have been handled above!"); + case Expectation::Kind::Member: if (haveCascade != wantsCascade) { diagnose(diags, expectation.MessageRange.begin(), diag::dependency_cascading_mismatch, wantsCascade, haveCascade); - return p.fail(); + return O.fail(); + } else { + return O.fullfill(); } - - return p.fullfill(); - }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - case Expectation::Kind::PotentialMember: - matchExpectationOrFail( - OM, expectation, - [&](Obligation &p) { - assert(p.getName().empty()); - const auto haveCascade = p.getCascades(); + case Expectation::Kind::PotentialMember: + assert(O.getName().empty()); if (haveCascade != wantsCascade) { diagnose(diags, expectation.MessageRange.begin(), diag::potential_dependency_cascading_mismatch, wantsCascade, haveCascade); - return p.fail(); + return O.fail(); + } else { + return O.fullfill(); } - - return p.fullfill(); - }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - case Expectation::Kind::Provides: - matchExpectationOrFail( - OM, expectation, [](Obligation &O) { return O.fullfill(); }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - case Expectation::Kind::DynamicMember: - matchExpectationOrFail( - OM, expectation, [](Obligation &O) { return O.fullfill(); }, - [&](const Expectation &e) { - diagnose( - diags, e.MessageRange.begin(), diag::missing_member_dependency, - static_cast(expectation.Info.Kind), e.MessageRange); - }); - break; - } + case Expectation::Kind::Provides: + case Expectation::Kind::DynamicMember: + return O.fullfill(); + } + + llvm_unreachable("Unhandled expectation kind!"); + }, + [&](const Expectation &e) { + diagnose(diags, e.MessageRange.begin(), + diag::missing_member_dependency, + static_cast(expectation.Info.Kind), e.MessageRange); + }); } return false; From cb4782cc949786ddc056349276149f0637456d9d Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 11 Aug 2020 15:58:34 -0700 Subject: [PATCH 083/663] [CSGen] Remove favoring based on literals from computeFavoredTypeForExpr --- lib/Sema/CSGen.cpp | 68 ++++------------------------------------------ 1 file changed, 5 insertions(+), 63 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index b4f0c1facc721..05ee7887251f5 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -79,22 +79,10 @@ namespace { /// Internal struct for tracking information about types within a series /// of "linked" expressions. (Such as a chain of binary operator invocations.) struct LinkedTypeInfo { - unsigned haveIntLiteral : 1; - unsigned haveFloatLiteral : 1; - unsigned haveStringLiteral : 1; + bool hasLiteral = false; llvm::SmallSet collectedTypes; llvm::SmallVector binaryExprs; - - LinkedTypeInfo() { - haveIntLiteral = false; - haveFloatLiteral = false; - haveStringLiteral = false; - } - - bool hasLiteral() { - return haveIntLiteral || haveFloatLiteral || haveStringLiteral; - } }; /// Walks an expression sub-tree, and collects information about expressions @@ -180,19 +168,9 @@ namespace { !CS.getType(expr)->hasTypeVariable()) { return { false, expr }; } - - if (isa(expr)) { - LTI.haveIntLiteral = true; - return { false, expr }; - } - - if (isa(expr)) { - LTI.haveFloatLiteral = true; - return { false, expr }; - } - - if (isa(expr)) { - LTI.haveStringLiteral = true; + + if (isa(expr)) { + LTI.hasLiteral = true; return { false, expr }; } @@ -331,7 +309,7 @@ namespace { auto simplifyBinOpExprTyVars = [&]() { // Don't attempt to do linking if there are // literals intermingled with other inferred types. - if (lti.hasLiteral()) + if (lti.hasLiteral) return; for (auto binExp1 : lti.binaryExprs) { @@ -391,42 +369,6 @@ namespace { simplifyBinOpExprTyVars(); return true; - } - - if (lti.haveFloatLiteral) { - if (auto floatProto = CS.getASTContext().getProtocol( - KnownProtocolKind::ExpressibleByFloatLiteral)) { - if (auto defaultType = TypeChecker::getDefaultType(floatProto, CS.DC)) { - if (!CS.getFavoredType(expr)) { - CS.setFavoredType(expr, defaultType.getPointer()); - } - return true; - } - } - } - - if (lti.haveIntLiteral) { - if (auto intProto = CS.getASTContext().getProtocol( - KnownProtocolKind::ExpressibleByIntegerLiteral)) { - if (auto defaultType = TypeChecker::getDefaultType(intProto, CS.DC)) { - if (!CS.getFavoredType(expr)) { - CS.setFavoredType(expr, defaultType.getPointer()); - } - return true; - } - } - } - - if (lti.haveStringLiteral) { - if (auto stringProto = CS.getASTContext().getProtocol( - KnownProtocolKind::ExpressibleByStringLiteral)) { - if (auto defTy = TypeChecker::getDefaultType(stringProto, CS.DC)) { - if (!CS.getFavoredType(expr)) { - CS.setFavoredType(expr, defTy.getPointer()); - } - return true; - } - } } return false; From 7cd920403d2005df6d18ff7c9c545467a2568577 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 5 Aug 2020 20:09:24 -0300 Subject: [PATCH 084/663] Fix reading metadata from ELF sections --- include/swift/Reflection/ReflectionContext.h | 170 ++++++++++++++----- 1 file changed, 124 insertions(+), 46 deletions(-) diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 06cc0dab587b5..c3818f477eaf6 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -22,6 +22,7 @@ #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/Memory.h" #include "swift/ABI/Enum.h" #include "swift/ABI/ObjectFile.h" @@ -393,29 +394,60 @@ class ReflectionContext return readPECOFFSections(ImageStart); } - template bool readELFSections(RemoteAddress ImageStart) { - auto Buf = - this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); + template + bool readELFSections(RemoteAddress ImageStart, + llvm::Optional FileBuffer) { + // When reading from the FileBuffer we can simply return a pointer to + // the underlying data. + // When reading from the process, we need to keep the memory around + // until the end of the function, so we store it inside ReadDataBuffer. + // We do this so in both cases we can return a simple pointer. + std::vector ReadDataBuffer; + auto readData = [&](uint64_t Offset, uint64_t Size) -> const void * { + if (FileBuffer.hasValue()) { + auto Buffer = FileBuffer.getValue(); + if (Offset + Size > Buffer.allocatedSize()) + return nullptr; + return (const void *)((uint64_t)Buffer.base() + Offset); + } else { + MemoryReader::ReadBytesResult Buf = + this->getReader().readBytes(ImageStart + Offset, Size); + if (!Buf) + return nullptr; + ReadDataBuffer.push_back(std::move(Buf)); + return ReadDataBuffer.back().get(); + } + }; - auto Hdr = reinterpret_cast(Buf.get()); + const void *Buf = readData(0, sizeof(typename T::Header)); + if (!Buf) + return false; + auto Hdr = reinterpret_cast(Buf); assert(Hdr->getFileClass() == T::ELFClass && "invalid ELF file class"); - // From the header, grab informations about the section header table. - auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff; - auto SectionHdrNumEntries = Hdr->e_shnum; - auto SectionEntrySize = Hdr->e_shentsize; + // From the header, grab information about the section header table. + uint64_t SectionHdrAddress = Hdr->e_shoff; + uint16_t SectionHdrNumEntries = Hdr->e_shnum; + uint16_t SectionEntrySize = Hdr->e_shentsize; + + if (sizeof(typename T::Section) > SectionEntrySize) + return false; + if (SectionHdrNumEntries == 0) + return false; // Collect all the section headers, we need them to look up the // reflection sections (by name) and the string table. + // We read the section headers from the FileBuffer, since they are + // not mapped in the child process. std::vector SecHdrVec; for (unsigned I = 0; I < SectionHdrNumEntries; ++I) { - auto SecBuf = this->getReader().readBytes( - RemoteAddress(SectionHdrAddress + (I * SectionEntrySize)), - SectionEntrySize); + uint64_t Offset = SectionHdrAddress + (I * SectionEntrySize); + auto SecBuf = readData(Offset, sizeof(typename T::Section)); if (!SecBuf) return false; - auto SecHdr = - reinterpret_cast(SecBuf.get()); + const typename T::Section *SecHdr = + reinterpret_cast(SecBuf); + SecHdrVec.push_back(SecHdr); } @@ -434,30 +466,54 @@ class ReflectionContext typename T::Offset StrTabOffset = SecHdrStrTab->sh_offset; typename T::Size StrTabSize = SecHdrStrTab->sh_size; - auto StrTabStart = - RemoteAddress(ImageStart.getAddressData() + StrTabOffset); - auto StrTabBuf = this->getReader().readBytes(StrTabStart, StrTabSize); - auto StrTab = reinterpret_cast(StrTabBuf.get()); - - auto findELFSectionByName = [&](llvm::StringRef Name) - -> std::pair, uint64_t> { - // Now for all the sections, find their name. - for (const typename T::Section *Hdr : SecHdrVec) { - uint32_t Offset = Hdr->sh_name; - auto SecName = std::string(StrTab + Offset); - if (SecName != Name) - continue; - auto SecStart = - RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); - auto SecSize = Hdr->sh_size; - auto SecBuf = this->getReader().readBytes(SecStart, SecSize); - auto SecContents = RemoteRef(SecStart.getAddressData(), - SecBuf.get()); - savedBuffers.push_back(std::move(SecBuf)); - return {SecContents, SecSize}; - } - return {nullptr, 0}; - }; + auto StrTabBuf = readData(StrTabOffset, StrTabSize); + if (!StrTabBuf) + return false; + auto StrTab = reinterpret_cast(StrTabBuf); + bool Error = false; + auto findELFSectionByName = + [&](llvm::StringRef Name) -> std::pair, uint64_t> { + if (Error) + return {nullptr, 0}; + // Now for all the sections, find their name. + for (const typename T::Section *Hdr : SecHdrVec) { + uint32_t Offset = Hdr->sh_name; + const char *Start = (const char *)StrTab + Offset; + uint64_t Size = strnlen(Start, StrTabSize - Offset); + if (Size > StrTabSize - Offset) { + Error = true; + break; + } + std::string SecName(Start, Size); + if (SecName != Name) + continue; + RemoteAddress SecStart = + RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); + auto SecSize = Hdr->sh_size; + MemoryReader::ReadBytesResult SecBuf; + if (FileBuffer.hasValue()) { + // sh_offset gives us the offset to the section in the file, + // while sh_addr gives us the offset in the process. + auto Offset = Hdr->sh_offset; + if (FileBuffer->allocatedSize() > Offset + Size) { + Error = true; + break; + } + auto *Buf = malloc(SecSize); + SecBuf = MemoryReader::ReadBytesResult( + Buf, [](const void *ptr) { free(const_cast(ptr)); }); + memcpy((void *)Buf, + (const void *)((uint64_t)FileBuffer->base() + Offset), Size); + } else { + SecBuf = this->getReader().readBytes(SecStart, SecSize); + } + auto SecContents = + RemoteRef(SecStart.getAddressData(), SecBuf.get()); + savedBuffers.push_back(std::move(SecBuf)); + return {SecContents, SecSize}; + } + return {nullptr, 0}; + }; SwiftObjectFileFormatELF ObjectFileFormat; auto FieldMdSec = findELFSectionByName( @@ -473,6 +529,9 @@ class ReflectionContext auto ReflStrMdSec = findELFSectionByName( ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); + if (Error) + return false; + // We succeed if at least one of the sections is present in the // ELF executable. if (FieldMdSec.first == nullptr && @@ -492,12 +551,28 @@ class ReflectionContext {ReflStrMdSec.first, ReflStrMdSec.second}}; this->addReflectionInfo(info); - - savedBuffers.push_back(std::move(Buf)); return true; } - - bool readELF(RemoteAddress ImageStart) { + + /// Parses metadata information from an ELF image. Because the Section + /// Header Table maybe be missing (for example, when reading from a + /// process) this method optionally receives a buffer with the contents + /// of the image's file, from where it will the necessary information. + /// + /// + /// \param[in] ImageStart + /// A remote address pointing to the start of the image in the running + /// process. + /// + /// \param[in] FileBuffer + /// A buffer which contains the contents of the image's file + /// in disk. If missing, all the information will be read using the + /// instance's memory reader. + /// + /// \return + /// /b True if the metadata information was parsed successfully, + /// /b false otherwise. + bool readELF(RemoteAddress ImageStart, llvm::Optional FileBuffer) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr)); @@ -510,9 +585,11 @@ class ReflectionContext // Check if we have a ELFCLASS32 or ELFCLASS64 unsigned char FileClass = Hdr->getFileClass(); if (FileClass == llvm::ELF::ELFCLASS64) { - return readELFSections>(ImageStart); + return readELFSections>( + ImageStart, FileBuffer); } else if (FileClass == llvm::ELF::ELFCLASS32) { - return readELFSections>(ImageStart); + return readELFSections>( + ImageStart, FileBuffer); } else { return false; } @@ -542,15 +619,16 @@ class ReflectionContext if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') { return readPECOFF(ImageStart); } - + + // ELF. if (MagicBytes[0] == llvm::ELF::ElfMagic[0] && MagicBytes[1] == llvm::ELF::ElfMagic[1] && MagicBytes[2] == llvm::ELF::ElfMagic[2] && MagicBytes[3] == llvm::ELF::ElfMagic[3]) { - return readELF(ImageStart); + return readELF(ImageStart, llvm::Optional()); } - + // We don't recognize the format. return false; } From 9cd06f7109e59e41835e4465ffd9c96baddf68ed Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 10 Aug 2020 17:23:42 -0700 Subject: [PATCH 085/663] [TypeChecker] NFC: Clarify another flaky conformance diagnostic (only on iOS 386 simulator) --- test/Sema/struct_equatable_hashable.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/Sema/struct_equatable_hashable.swift b/test/Sema/struct_equatable_hashable.swift index be162f1abd1a2..5ffbb14a68bda 100644 --- a/test/Sema/struct_equatable_hashable.swift +++ b/test/Sema/struct_equatable_hashable.swift @@ -114,8 +114,10 @@ struct StructWithoutExplicitConformance { } func structWithoutExplicitConformance() { + // FIXME(rdar://problem/64844584) - on iOS simulator this diagnostic is flaky // This diagnostic is about `Equatable` because it's considered the best possible solution among other ones for operator `==`. - if StructWithoutExplicitConformance(a: 1, b: "b") == StructWithoutExplicitConformance(a: 2, b: "a") { } // expected-error{{referencing operator function '==' on 'Equatable' requires that 'StructWithoutExplicitConformance' conform to 'Equatable'}} + if StructWithoutExplicitConformance(a: 1, b: "b") == StructWithoutExplicitConformance(a: 2, b: "a") { } + // expected-error@-1 {{requires that 'StructWithoutExplicitConformance' conform to 'Equatable'}} } // Structs with non-hashable/equatable stored properties don't derive conformance. From 1ab4a4742ae7dbf0df3be48b298546f537bc402e Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 11 Aug 2020 17:08:27 -0700 Subject: [PATCH 086/663] [AST] Formalize getBodySourceRange() for fast completion Fast completion replaces the body ('BraceStmt') of function decls with other bodies parsed from different source buffers from the original source buffer. That means the source range of the body and the location of the function declaration itself might be in different buffers. Previously, FuncDecl::getSourceRange() used to use the 'func' keyword decl as the start loc and 'getBodySourceRange().End' as the end loc. This breaks a SourceRange invariant where the start and end loc must be in the same buffer. This patch add a new function 'getOriginalBodySourceRange()' which always return the source range of the original body of the function. And use that from 'getSourceRange()' functions. The orignal body source range is stored in a side table in ASTContext so that normal compilation doesn't consume space for that extra info. --- include/swift/AST/Decl.h | 15 +++++++++++++++ lib/AST/ASTContext.cpp | 34 ++++++++++++++++++++++++++++++++++ lib/AST/Decl.cpp | 21 ++++++++++++++++++--- lib/IDE/CompletionInstance.cpp | 7 +++++-- 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index e3fb02109d10b..67e39b9800ef4 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5942,6 +5942,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { setBodyKind(BodyKind::Unparsed); } + void setBodyToBeReparsed(SourceRange bodyRange); + /// Provide the parsed body for the function. void setBodyParsed(BraceStmt *S) { setBody(S, BodyKind::Parsed); @@ -6007,6 +6009,19 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// Retrieve the source range of the function body. SourceRange getBodySourceRange() const; + /// Keep current \c getBodySourceRange() as the "original" body source range + /// iff the this method hasn't been called on this object. The current body + /// source range must be in the same buffer as the location of the declaration + /// itself. + void keepOriginalBodySourceRange(); + + /// Retrieve the source range of the *original* function body. + /// + /// This may be different from \c getBodySourceRange() that returns the source + /// range of the *current* body. It happens when the body is parsed from other + /// source buffers for e.g. code-completion. + SourceRange getOriginalBodySourceRange() const; + /// Retrieve the source range of the function declaration name + patterns. SourceRange getSignatureSourceRange() const; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f95561eb4befd..ca7f74f5f9248 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -339,6 +339,10 @@ struct ASTContext::Implementation { /// LiteralExprs in fully-checked AST. llvm::DenseMap BuiltinInitWitness; + /// Mapping from the function decl to its original body's source range. This + /// is populated if the body is reparsed from other source buffers. + llvm::DenseMap OriginalBodySourceRanges; + /// Structure that captures data that is segregated into different /// arenas. struct Arena { @@ -4778,6 +4782,36 @@ void VarDecl::setOriginalWrappedProperty(VarDecl *originalProperty) { ctx.getImpl().OriginalWrappedProperties[this] = originalProperty; } +#ifndef NDEBUG +static bool isSourceLocInOrignalBuffer(const Decl *D, SourceLoc Loc) { + assert(Loc.isValid()); + auto bufferID = D->getDeclContext()->getParentSourceFile()->getBufferID(); + assert(bufferID.hasValue() && "Source buffer ID must be set"); + auto &SM = D->getASTContext().SourceMgr; + return SM.getRangeForBuffer(*bufferID).contains(Loc); +} +#endif + +void AbstractFunctionDecl::keepOriginalBodySourceRange() { + auto &impl = getASTContext().getImpl(); + auto result = + impl.OriginalBodySourceRanges.insert({this, getBodySourceRange()}); + assert((!result.second || + isSourceLocInOrignalBuffer(this, result.first->getSecond().Start)) && + "This function must be called before setting new body range"); + (void)result; +} + +SourceRange AbstractFunctionDecl::getOriginalBodySourceRange() const { + auto &impl = getASTContext().getImpl(); + auto found = impl.OriginalBodySourceRanges.find(this); + if (found != impl.OriginalBodySourceRanges.end()) { + return found->getSecond(); + } else { + return getBodySourceRange(); + } +} + IndexSubset * IndexSubset::get(ASTContext &ctx, const SmallBitVector &indices) { auto &foldingSet = ctx.getImpl().IndexSubsets; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0b0816acd18b0..1e34a4af48150 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6726,6 +6726,21 @@ void AbstractFunctionDecl::setBody(BraceStmt *S, BodyKind NewBodyKind) { } } +void AbstractFunctionDecl::setBodyToBeReparsed(SourceRange bodyRange) { + assert(bodyRange.isValid()); + assert(getBodyKind() == BodyKind::None || + getBodyKind() == BodyKind::Skipped || + getBodyKind() == BodyKind::Parsed || + getBodyKind() == BodyKind::TypeChecked); + assert(getASTContext().SourceMgr.rangeContainsTokenLoc( + bodyRange, getASTContext().SourceMgr.getCodeCompletionLoc()) && + "This function is only intended to be used for code completion"); + + keepOriginalBodySourceRange(); + BodyRange = bodyRange; + setBodyKind(BodyKind::Unparsed); +} + SourceRange AbstractFunctionDecl::getBodySourceRange() const { switch (getBodyKind()) { case BodyKind::None: @@ -7386,7 +7401,7 @@ SourceRange FuncDecl::getSourceRange() const { getBodyKind() == BodyKind::Skipped) return { StartLoc, BodyRange.End }; - SourceLoc RBraceLoc = getBodySourceRange().End; + SourceLoc RBraceLoc = getOriginalBodySourceRange().End; if (RBraceLoc.isValid()) { return { StartLoc, RBraceLoc }; } @@ -7507,7 +7522,7 @@ SourceRange ConstructorDecl::getSourceRange() const { if (isImplicit()) return getConstructorLoc(); - SourceLoc End = getBodySourceRange().End; + SourceLoc End = getOriginalBodySourceRange().End; if (End.isInvalid()) End = getGenericTrailingWhereClauseSourceRange().End; if (End.isInvalid()) @@ -7733,7 +7748,7 @@ ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags, } SourceRange DestructorDecl::getSourceRange() const { - SourceLoc End = getBodySourceRange().End; + SourceLoc End = getOriginalBodySourceRange().End; if (End.isInvalid()) { End = getDestructorLoc(); } diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 26df36591975f..26842a4c21622 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -411,9 +411,12 @@ bool CompletionInstance::performCachedOperationIfPossible( oldInfo.PrevOffset = newInfo.PrevOffset; oldState->restoreCodeCompletionDelayedDeclState(oldInfo); + auto newBufferStart = SM.getRangeForBuffer(newBufferID).getStart(); + SourceRange newBodyRange(newBufferStart.getAdvancedLoc(newInfo.StartOffset), + newBufferStart.getAdvancedLoc(newInfo.EndOffset)); + auto *AFD = cast(DC); - if (AFD->isBodySkipped()) - AFD->setBodyDelayed(AFD->getBodySourceRange()); + AFD->setBodyToBeReparsed(newBodyRange); traceDC = AFD; break; From 5ad4fa8b07174671b55501b508153eabc9b429a8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 11 Aug 2020 22:52:36 -0400 Subject: [PATCH 087/663] SIL: Don't canonicalize struct field and enum element types against the wrong signature The replacement types of the substitution map are either going to be contextual types, or interface types using some generic signature. There is no requirement that this generic signature is the generic signature of the type declaration itself. By using the generic signature of the type declaration, we could incorrectly canonicalize generic parameters to concrete types if the type itself was defined in a constrained extension, as in the test case here. Fixes . --- lib/SIL/IR/SILFunctionType.cpp | 2 +- lib/SIL/IR/TypeLowering.cpp | 4 ++-- .../rdar65272763.swift | 21 +++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 validation-test/compiler_crashers_2_fixed/rdar65272763.swift diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 60f7584418787..3838b09d1aef3 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -1304,7 +1304,7 @@ class SubstFunctionTypeCollector { if (origContextType->hasTypeParameter()) { origContextType = origSig->getGenericEnvironment() ->mapTypeIntoContext(origContextType) - ->getCanonicalType(origSig); + ->getCanonicalType(); } auto result = origContextType diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index ab879445ebc0a..06587a67372ea 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -1623,7 +1623,7 @@ namespace { for (auto field : D->getStoredProperties()) { auto substFieldType = field->getInterfaceType().subst(subMap) - ->getCanonicalType(D->getGenericSignature()); + ->getCanonicalType(); // We are determining the recursive properties of the struct here, // not the lowered types of the fields, so instead of lowering the @@ -1676,7 +1676,7 @@ namespace { auto substEltType = elt->getArgumentInterfaceType().subst(subMap) - ->getCanonicalType(D->getGenericSignature()); + ->getCanonicalType(); auto origEltType = origType.unsafeGetSubstFieldType(elt, elt->getArgumentInterfaceType() diff --git a/validation-test/compiler_crashers_2_fixed/rdar65272763.swift b/validation-test/compiler_crashers_2_fixed/rdar65272763.swift new file mode 100644 index 0000000000000..f3233a7afd131 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar65272763.swift @@ -0,0 +1,21 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public struct S1 {} +public extension S1 where T1 == Int { + public struct S2 { + let value: T2 + + public init(value: T2) { + self.value = value + } + } + + public init(s: [S2]) { + self.init() + + s.forEach { _ in + + } + } +} + From db2dd20ce6ab7be8d38dbe311744e68f7abfa99d Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Tue, 11 Aug 2020 14:07:41 -0700 Subject: [PATCH 088/663] Parse concurrency syntax when parsing for syntax-tree-only mode. This allows the syntax parser library and SwiftSyntax to successfully parse code using this experimental feature without requiring an API to pass compiler flags into the parser. --- include/swift/Parse/Parser.h | 8 ++++++ lib/Parse/ParseExpr.cpp | 9 +++--- lib/Parse/ParsePattern.cpp | 4 +-- lib/Parse/ParseType.cpp | 10 +++---- test/Syntax/Parser/async.swift | 28 +++++++++++++++++++ tools/swift-syntax-test/swift-syntax-test.cpp | 1 - 6 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 test/Syntax/Parser/async.swift diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 2d2119941cd51..723fdcd956a22 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -688,6 +688,14 @@ class Parser { Optional getStringLiteralIfNotInterpolated(SourceLoc Loc, StringRef DiagText); + /// Returns true to indicate that experimental concurrency syntax should be + /// parsed if the parser is generating only a syntax tree or if the user has + /// passed the `-enable-experimental-concurrency` flag to the frontend. + bool shouldParseExperimentalConcurrency() const { + return Context.LangOpts.EnableExperimentalConcurrency || + Context.LangOpts.ParseForSyntaxTreeOnly; + } + public: InFlightDiagnostic diagnose(SourceLoc Loc, Diagnostic Diag) { if (Diags.isDiagnosticPointsToFirstBadToken(Diag.getID()) && diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index a22f077316840..94aef231ec5d3 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -330,7 +330,7 @@ ParserResult Parser::parseExprSequence(Diag<> Message, case tok::identifier: { // 'async' followed by 'throws' or '->' implies that we have an arrow // expression. - if (!(Context.LangOpts.EnableExperimentalConcurrency && + if (!(shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async") && peekToken().isAny(tok::arrow, tok::kw_throws))) goto done; @@ -392,8 +392,7 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, SyntaxParsingContext ElementContext(SyntaxContext, SyntaxContextKind::Expr); - if (Context.LangOpts.EnableExperimentalConcurrency && - Tok.is(tok::kw___await)) { + if (shouldParseExperimentalConcurrency() && Tok.is(tok::kw___await)) { SourceLoc awaitLoc = consumeToken(tok::kw___await); ParserResult sub = parseExprUnary(message, isExprBasic); if (!sub.hasCodeCompletion() && !sub.isNull()) { @@ -2448,7 +2447,7 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, // Consume 'async', 'throws', and 'rethrows', but in any order. auto consumeAsyncThrows = [&] { bool hadAsync = false; - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { consumeToken(); hadAsync = true; @@ -2457,7 +2456,7 @@ parseClosureSignatureIfPresent(SourceRange &bracketRange, if (!consumeIf(tok::kw_throws) && !consumeIf(tok::kw_rethrows)) return; - if (Context.LangOpts.EnableExperimentalConcurrency && !hadAsync && + if (shouldParseExperimentalConcurrency() && !hadAsync && Tok.isContextualKeyword("async")) { consumeToken(); } diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 06b75b7c2df5f..e26a0dd1cd238 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -824,7 +824,7 @@ Parser::parseFunctionSignature(Identifier SimpleName, void Parser::parseAsyncThrows( SourceLoc existingArrowLoc, SourceLoc &asyncLoc, SourceLoc &throwsLoc, bool *rethrows) { - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); @@ -857,7 +857,7 @@ void Parser::parseAsyncThrows( .fixItInsert(existingArrowLoc, (keyword + " ").str()); } - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index aefea2401c15a..8dc5795905458 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -412,7 +412,7 @@ ParserResult Parser::parseType(Diag<> MessageID, // Parse an async specifier. SourceLoc asyncLoc; - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); } @@ -423,7 +423,7 @@ ParserResult Parser::parseType(Diag<> MessageID, SourceLoc throwsLoc; if (Tok.isAny(tok::kw_throws, tok::kw_rethrows, tok::kw_throw, tok::kw_try) && (peekToken().is(tok::arrow) || - (Context.LangOpts.EnableExperimentalConcurrency && + (shouldParseExperimentalConcurrency() && peekToken().isContextualKeyword("async")))) { if (Tok.isAny(tok::kw_rethrows, tok::kw_throw, tok::kw_try)) { // 'rethrows' is only allowed on function declarations for now. @@ -436,7 +436,7 @@ ParserResult Parser::parseType(Diag<> MessageID, throwsLoc = consumeToken(); // 'async' must preceed 'throws'; accept this but complain. - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { asyncLoc = consumeToken(); @@ -1589,7 +1589,7 @@ bool Parser::canParseType() { } // Handle type-function if we have an 'async'. - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) { consumeToken(); @@ -1605,7 +1605,7 @@ bool Parser::canParseType() { // Allow 'async' here even though it is ill-formed, so we can provide // a better error. - if (Context.LangOpts.EnableExperimentalConcurrency && + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("async")) consumeToken(); diff --git a/test/Syntax/Parser/async.swift b/test/Syntax/Parser/async.swift new file mode 100644 index 0000000000000..c04b6f9f956e7 --- /dev/null +++ b/test/Syntax/Parser/async.swift @@ -0,0 +1,28 @@ +// Verify that async parses correctly via the parser lib even without the +// experimental flag being set in LangOpts. +// +// REQUIRES: syntax_parser_lib +// RUN: %swift-syntax-parser-test %s -dump-diags 2>&1 | %FileCheck %s + +func asyncGlobal1() async { } +func asyncGlobal2() async throws { } + +typealias AsyncFunc1 = () async -> () +typealias AsyncFunc2 = () async throws -> () + +func testTypeExprs() { + let _ = [() async -> ()]() + let _ = [() async throws -> ()]() +} + +func testAwaitOperator() async { + let _ = __await asyncGlobal1() +} + +func testAsyncClosure() { + let _ = { () async in 5 } + let _ = { () throws in 5 } + let _ = { () async throws in 5 } +} + +// CHECK: 0 error(s) 0 warnings(s) 0 note(s) diff --git a/tools/swift-syntax-test/swift-syntax-test.cpp b/tools/swift-syntax-test/swift-syntax-test.cpp index 7edcaae19779c..c492162111927 100644 --- a/tools/swift-syntax-test/swift-syntax-test.cpp +++ b/tools/swift-syntax-test/swift-syntax-test.cpp @@ -610,7 +610,6 @@ int parseFile( Invocation.getLangOptions().VerifySyntaxTree = options::VerifySyntaxTree; Invocation.getLangOptions().RequestEvaluatorGraphVizPath = options::GraphVisPath; Invocation.getLangOptions().DisablePoundIfEvaluation = true; - Invocation.getLangOptions().EnableExperimentalConcurrency = true; Invocation.getFrontendOptions().InputsAndOutputs.addInputFile(InputFileName); From bf2ef3934d73ffe0bb8cb5397732de3a814eef18 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Tue, 11 Aug 2020 22:20:58 -0700 Subject: [PATCH 089/663] [AutoDiff] NFC: make LinearFunctionExtractInst inherit UnaryInstructionBase. (#33418) Remove ad-hoc operand list and operand getters. --- include/swift/SIL/SILCloner.h | 8 ++++---- include/swift/SIL/SILInstruction.h | 11 ++--------- lib/IRGen/IRGenSIL.cpp | 4 ++-- lib/IRGen/LoadableByAddress.cpp | 2 +- lib/SIL/IR/SILInstructions.cpp | 8 ++++---- lib/SIL/IR/SILPrinter.cpp | 2 +- lib/SIL/Verifier/SILVerifier.cpp | 2 +- lib/Serialization/SerializeSIL.cpp | 4 ++-- 8 files changed, 17 insertions(+), 24 deletions(-) diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index e7c544992dddc..c27d345ee8ae2 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -2905,10 +2905,10 @@ template void SILCloner:: visitLinearFunctionExtractInst(LinearFunctionExtractInst *Inst) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createLinearFunctionExtract( - getOpLocation(Inst->getLoc()), Inst->getExtractee(), - getOpValue(Inst->getFunctionOperand()))); + recordClonedInstruction(Inst, getBuilder().createLinearFunctionExtract( + getOpLocation(Inst->getLoc()), + Inst->getExtractee(), + getOpValue(Inst->getOperand()))); } template diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index d504f37085831..36ebd2ef858da 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -8364,14 +8364,11 @@ class DifferentiableFunctionExtractInst /// representing a bundle of the original function and the transpose function, /// extract the specified function. class LinearFunctionExtractInst - : public InstructionBase< - SILInstructionKind::LinearFunctionExtractInst, - SingleValueInstruction> { + : public UnaryInstructionBase { private: /// The extractee. LinearDifferentiableFunctionTypeComponent extractee; - /// The list containing the `@differentiable(linear)` function operand. - FixedOperandList<1> operands; static SILType getExtracteeType(SILValue function, @@ -8387,10 +8384,6 @@ class LinearFunctionExtractInst LinearDifferentiableFunctionTypeComponent getExtractee() const { return extractee; } - - SILValue getFunctionOperand() const { return operands[0].get(); } - ArrayRef getAllOperands() const { return operands.asArray(); } - MutableArrayRef getAllOperands() { return operands.asArray(); } }; /// DifferentiabilityWitnessFunctionInst - Looks up a differentiability witness diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 8c0562c7df300..50b443d50419a 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1937,12 +1937,12 @@ void IRGenSILFunction:: visitLinearFunctionExtractInst(LinearFunctionExtractInst *i) { unsigned structFieldOffset = i->getExtractee().rawValue; unsigned fieldSize = 1; - auto fnRepr = i->getFunctionOperand()->getType().getFunctionRepresentation(); + auto fnRepr = i->getOperand()->getType().getFunctionRepresentation(); if (fnRepr == SILFunctionTypeRepresentation::Thick) { structFieldOffset *= 2; fieldSize = 2; } - auto diffFnExp = getLoweredExplosion(i->getFunctionOperand()); + auto diffFnExp = getLoweredExplosion(i->getOperand()); assert(diffFnExp.size() == fieldSize * 2); Explosion e; e.add(diffFnExp.getRange(structFieldOffset, structFieldOffset + fieldSize)); diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 8ec81868638ce..2a509cbfeeb89 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -2862,7 +2862,7 @@ bool LoadableByAddress::recreateConvInstr(SILInstruction &I, case SILInstructionKind::LinearFunctionExtractInst: { auto instr = cast(convInstr); newInstr = convBuilder.createLinearFunctionExtract( - instr->getLoc(), instr->getExtractee(), instr->getFunctionOperand()); + instr->getLoc(), instr->getExtractee(), instr->getOperand()); break; } default: diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index 1faa9ec6ae6a1..bef2b17c534bc 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -762,10 +762,10 @@ getExtracteeType( LinearFunctionExtractInst::LinearFunctionExtractInst( SILModule &module, SILDebugLocation debugLoc, - LinearDifferentiableFunctionTypeComponent extractee, SILValue theFunction) - : InstructionBase(debugLoc, - getExtracteeType(theFunction, extractee, module)), - extractee(extractee), operands(this, theFunction) {} + LinearDifferentiableFunctionTypeComponent extractee, SILValue function) + : UnaryInstructionBase(debugLoc, function, + getExtracteeType(function, extractee, module)), + extractee(extractee) {} SILType DifferentiabilityWitnessFunctionInst::getDifferentiabilityWitnessType( SILModule &module, DifferentiabilityWitnessFunctionKind witnessKind, diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index bb84c23ef1e4c..eed8fab9abf36 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2397,7 +2397,7 @@ class SILPrinter : public SILInstructionVisitor { break; } *this << "] "; - *this << getIDAndType(lfei->getFunctionOperand()); + *this << getIDAndType(lfei->getOperand()); } void visitDifferentiabilityWitnessFunctionInst( diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 70d2a8d7ad752..c2f3de4038027 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -4730,7 +4730,7 @@ class SILVerifier : public SILVerifierBase { } void checkLinearFunctionExtractInst(LinearFunctionExtractInst *lfei) { - auto fnTy = lfei->getFunctionOperand()->getType().getAs(); + auto fnTy = lfei->getOperand()->getType().getAs(); require(fnTy, "The function operand must have a function type"); require(fnTy->getDifferentiabilityKind() == DifferentiabilityKind::Linear, "The function operand must be a '@differentiable(linear)' " diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 00e9443213ea0..1c254ae5f3462 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -2240,8 +2240,8 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { } case SILInstructionKind::LinearFunctionExtractInst: { auto *lfei = cast(&SI); - auto operandRef = addValueRef(lfei->getFunctionOperand()); - auto operandType = lfei->getFunctionOperand()->getType(); + auto operandRef = addValueRef(lfei->getOperand()); + auto operandType = lfei->getOperand()->getType(); auto operandTypeRef = S.addTypeRef(operandType.getASTType()); auto rawExtractee = (unsigned)lfei->getExtractee(); SILInstLinearFunctionExtractLayout::emitRecord(Out, ScratchRecord, From 7594cfb0bc620ff12fb41319f7eb830e4fade62e Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Mon, 10 Aug 2020 16:51:58 +1000 Subject: [PATCH 090/663] [Parse] Update Lexer::getLocFor*Line methods to return correct locations When the location given to getLocForStartOfLine was an empty line, it would actually return the location of the next line rather than the given location as it should. If the location given to getLocForEndOfLine was inside a token on a line that was either empty or contained whitespace, it would skip to the end of that token and then return the location for the next line. This was an issue for multiline strings, where the string is a single token but it's over multiple lines. --- include/swift/Parse/Lexer.h | 2 +- lib/Parse/Lexer.cpp | 27 ++++++++++++--------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index 8cd9b75a415c7..68663f19a3c4e 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -352,7 +352,7 @@ class Lexer { static SourceLoc getLocForStartOfLine(SourceManager &SM, SourceLoc Loc); /// Retrieve the source location for the end of the line containing the - /// given token, which is the location of the start of the next line. + /// given location, which is the location of the start of the next line. static SourceLoc getLocForEndOfLine(SourceManager &SM, SourceLoc Loc); /// Retrieve the string used to indent the line that contains the given diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index 976b3b2aeee92..fef46453c959e 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -2706,12 +2706,12 @@ static SourceLoc getLocForStartOfTokenInBuf(SourceManager &SM, // Find the start of the given line. static const char *findStartOfLine(const char *bufStart, const char *current) { while (current != bufStart) { - if (current[0] == '\n' || current[0] == '\r') { + --current; + + if (current[0] == '\n') { ++current; break; } - - --current; } return current; @@ -2779,19 +2779,16 @@ SourceLoc Lexer::getLocForEndOfLine(SourceManager &SM, SourceLoc Loc) { if (BufferID < 0) return SourceLoc(); - // Use fake language options; language options only affect validity - // and the exact token produced. - LangOptions FakeLangOpts; + CharSourceRange entireRange = SM.getRangeForBuffer(BufferID); + StringRef Buffer = SM.extractText(entireRange); - // Here we return comments as tokens because either the caller skipped - // comments and normally we won't be at the beginning of a comment token - // (making this option irrelevant), or the caller lexed comments and - // we need to lex just the comment token. - Lexer L(FakeLangOpts, SM, BufferID, nullptr, LexerMode::Swift, - HashbangMode::Allowed, CommentRetentionMode::ReturnAsTokens); - L.restoreState(State(Loc)); - L.skipToEndOfLine(/*EatNewline=*/true); - return getSourceLoc(L.CurPtr); + // Windows line endings are \r\n. Since we want the start of the next + // line, just look for \n so the \r is skipped through. + size_t Offset = SM.getLocOffsetInBuffer(Loc, BufferID); + Offset = Buffer.find('\n', Offset); + if (Offset == StringRef::npos) + return SourceLoc(); + return getSourceLoc(Buffer.data() + Offset + 1); } StringRef Lexer::getIndentationForLine(SourceManager &SM, SourceLoc Loc, From ef89b0dc51ddd731f90fcf0f71738e9190f767db Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Wed, 12 Aug 2020 07:28:34 -0700 Subject: [PATCH 091/663] Add a 'standalone_minimal' preset to build a minimal, static, OS independent, self-contained binaries of stdlib. (#33286) --- cmake/modules/AddSwift.cmake | 6 ++- cmake/modules/DarwinSDKs.cmake | 18 +++++++++ stdlib/cmake/modules/AddSwiftStdlib.cmake | 6 ++- stdlib/cmake/modules/SwiftSource.cmake | 23 ++++++++--- test/CMakeLists.txt | 1 + utils/build-presets.ini | 38 +++++++++++++++++++ utils/build-script-impl | 26 +++++++++++++ .../build_swift/driver_arguments.py | 5 +++ utils/build_swift/tests/expected_options.py | 2 + .../swift_build_support/targets.py | 7 ++++ 10 files changed, 124 insertions(+), 8 deletions(-) diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index c9f4f8208ec7a..604870d28b6e3 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -131,7 +131,11 @@ function(_add_host_variant_c_compile_flags target) is_build_type_optimized("${CMAKE_BUILD_TYPE}" optimized) if(optimized) - target_compile_options(${target} PRIVATE -O2) + if("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel") + target_compile_options(${target} PRIVATE -Os) + else() + target_compile_options(${target} PRIVATE -O2) + endif() # Omit leaf frame pointers on x86 production builds (optimized, no debug # info, and no asserts). diff --git a/cmake/modules/DarwinSDKs.cmake b/cmake/modules/DarwinSDKs.cmake index 20a5620fba6a7..dc570b7005834 100644 --- a/cmake/modules/DarwinSDKs.cmake +++ b/cmake/modules/DarwinSDKs.cmake @@ -26,6 +26,24 @@ if(swift_build_osx) configure_target_variant(OSX-R "OS X Release" OSX R "Release") endif() +is_sdk_requested(FREESTANDING swift_build_freestanding) +if(swift_build_freestanding) + set(SWIFT_FREESTANDING_SDK "" CACHE STRING + "Which SDK to use when building the FREESTANDING stdlib") + set(SWIFT_FREESTANDING_TRIPLE_NAME "" CACHE STRING + "Which triple name (e.g. 'none-macho') to use when building the FREESTANDING stdlib") + set(SWIFT_FREESTANDING_ARCHS "" CACHE STRING + "Which architectures to build when building the FREESTANDING stdlib") + configure_sdk_darwin( + FREESTANDING "FREESTANDING" "" + "${SWIFT_FREESTANDING_SDK}" freestanding "${SWIFT_FREESTANDING_TRIPLE_NAME}" freestanding "${SWIFT_FREESTANDING_ARCHS}") + set(SWIFT_SDK_FREESTANDING_LIB_SUBDIR "freestanding") + configure_target_variant(FREESTANDING-DA "FREESTANDING Debug+Asserts" FREESTANDING DA "Debug+Asserts") + configure_target_variant(FREESTANDING-RA "FREESTANDING Release+Asserts" FREESTANDING RA "Release+Asserts") + configure_target_variant(FREESTANDING-R "FREESTANDING Release" FREESTANDING R "Release") + configure_target_variant(FREESTANDING-S "FREESTANDING MinSizeRelease" FREESTANDING S "MinSizeRelease") +endif() + # Compatible cross-compile SDKS for Darwin OSes: IOS, IOS_SIMULATOR, TVOS, # TVOS_SIMULATOR, WATCHOS, WATCHOS_SIMULATOR (archs hardcoded below). diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 2d9c5130dff04..1536bd0422411 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -180,7 +180,11 @@ function(_add_target_variant_c_compile_flags) is_build_type_optimized("${CFLAGS_BUILD_TYPE}" optimized) if(optimized) - list(APPEND result "-O2") + if("${CFLAGS_BUILD_TYPE}" STREQUAL "MinSizeRel") + list(APPEND result "-Os") + else() + list(APPEND result "-O2") + endif() # Omit leaf frame pointers on x86 production builds (optimized, no debug # info, and no asserts). diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index 5cc168883f3fd..59ec8d1d2bf46 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -11,6 +11,21 @@ function(compute_library_subdir result_var_name sdk arch) endif() endfunction() +# Return a swiftc flag (e.g. -O or -Onone) to control optimization level based +# on the build type. +function(swift_optimize_flag_for_build_type build_type result_var_name) + if("${build_type}" STREQUAL "Debug") + set("${result_var_name}" "-Onone" PARENT_SCOPE) + elseif("${build_type}" STREQUAL "RelWithDebInfo" OR + "${build_type}" STREQUAL "Release") + set("${result_var_name}" "-O" PARENT_SCOPE) + elseif("${build_type}" STREQUAL "MinSizeRel") + set("${result_var_name}" "-Osize" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unknown build type: ${build_type}") + endif() +endfunction() + # Process the sources within the given variable, pulling out any Swift # sources to be compiled with 'swift' directly. This updates # ${sourcesvar} in place with the resulting list and ${externalvar} with the @@ -230,12 +245,8 @@ function(_add_target_variant_swift_compile_flags "-F${SWIFT_SDK_${sdk}_ARCH_${arch}_PATH}/../../../Developer/Library/Frameworks") endif() - is_build_type_optimized("${build_type}" optimized) - if(optimized) - list(APPEND result "-O") - else() - list(APPEND result "-Onone") - endif() + swift_optimize_flag_for_build_type("${CMAKE_BUILD_TYPE}" optimize_flag) + list(APPEND result "${optimize_flag}") is_build_type_with_debuginfo("${build_type}" debuginfo) if(debuginfo) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4513359e3e5d7..ec8710ec76948 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -102,6 +102,7 @@ function(get_test_dependencies SDK result_var_name) ("${SDK}" STREQUAL "IOS_SIMULATOR") OR ("${SDK}" STREQUAL "TVOS_SIMULATOR") OR ("${SDK}" STREQUAL "WATCHOS_SIMULATOR") OR + ("${SDK}" STREQUAL "FREESTANDING") OR ("${SDK}" STREQUAL "LINUX") OR ("${SDK}" STREQUAL "CYGWIN") OR ("${SDK}" STREQUAL "FREEBSD") OR diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 9eaa76a841a99..bf3868dfc97c4 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2365,6 +2365,44 @@ mixin-preset=stdlib_DA_standalone,build test validation-test +[preset: stdlib_S_standalone,build] +mixin-preset=stdlib_base_standalone + +build-subdir=stdlib_S_standalone +min-size-release +no-assertions + +verbose-build + +[preset: stdlib_SA_standalone,build] +mixin-preset=stdlib_base_standalone + +build-subdir=stdlib_SA_standalone +min-size-release +assertions + +verbose-build + +[preset: mixin_stdlib_minimal] +enable-experimental-differentiable-programming=0 +enable-experimental-concurrency=0 +build-swift-dynamic-sdk-overlay=0 +build-swift-dynamic-stdlib=0 +build-swift-static-stdlib=1 + +[preset: stdlib_S_standalone_minimal_macho_x86_64,build] +mixin-preset= + stdlib_S_standalone,build + mixin_stdlib_minimal + +stdlib-deployment-targets=freestanding-x86_64 +swift-primary-variant-sdk=FREESTANDING +swift-primary-variant-arch=x86_64 +swift-freestanding-sdk=macosx +# For now, until clang/swiftc works correctly with "none-macho" as the OS part of target triple. +swift-freestanding-triple-name=macosx11.0 +swift-freestanding-archs=x86_64 + #===----------------------------------------------------------------------===# # Preset for Source Compatibility Suite #===----------------------------------------------------------------------===# diff --git a/utils/build-script-impl b/utils/build-script-impl index 148f946e19544..7a427b7c43d39 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -193,6 +193,11 @@ KNOWN_SETTINGS=( sil-verify-all "0" "If enabled, run the SIL verifier after each transform when building Swift files during this build process" stdlib-deployment-targets "" "space-separated list of targets to configure the Swift standard library to be compiled or cross-compiled for" + ## FREESTANDING Stdlib Options + swift-freestanding-sdk "" "which SDK to use when building the FREESTANDING stdlib" + swift-freestanding-triple-name "" "which triple name (e.g. 'none-macho') to use when building the FREESTANDING stdlib" + swift-freestanding-archs "" "space-separated list of which architectures to build when building the FREESTANDING stdlib" + ## Uncategorised install-prefix "" "installation prefix" toolchain-prefix "" "the path to the .xctoolchain directory that houses the install prefix path" @@ -1832,6 +1837,27 @@ for host in "${ALL_HOSTS[@]}"; do ) fi + if [ "${SWIFT_FREESTANDING_SDK}" ] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_FREESTANDING_SDK:STRING="${SWIFT_FREESTANDING_SDK}" + ) + fi + + if [ "${SWIFT_FREESTANDING_TRIPLE_NAME}" ] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_FREESTANDING_TRIPLE_NAME:STRING="${SWIFT_FREESTANDING_TRIPLE_NAME}" + ) + fi + + if [[ "${SWIFT_FREESTANDING_ARCHS}" ]] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_FREESTANDING_ARCHS:STRING="$(join ";" ${SWIFT_FREESTANDING_ARCHS[@]})" + ) + fi + if [[ ! "${SKIP_BUILD_LLDB}" ]] ; then lldb_build_dir=$(build_directory ${host} lldb) cmake_options=( diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 40959dd529d1e..62acc4557d027 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -680,6 +680,11 @@ def create_argument_parser(): help='build the Release variant of everything (default is ' '%(default)s)') + option(['--min-size-release'], store('build_variant'), + const='MinSizeRel', + help='build the MinSizeRel variant of everything (default is ' + '%(default)s)') + # ------------------------------------------------------------------------- in_group('Override build variant for a specific project') diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py index bbcd8577d94b3..9864063b6e7bb 100644 --- a/utils/build_swift/tests/expected_options.py +++ b/utils/build_swift/tests/expected_options.py @@ -412,6 +412,8 @@ class BuildScriptImplOption(_BaseOption): SetOption('--release', dest='build_variant', value='Release'), SetOption('--release-debuginfo', dest='build_variant', value='RelWithDebInfo'), + SetOption('--min-size-release', + dest='build_variant', value='MinSizeRel'), SetOption('--xcode', dest='cmake_generator', value='Xcode'), SetOption('-R', dest='build_variant', value='Release'), SetOption('-d', dest='build_variant', value='Debug'), diff --git a/utils/swift_build_support/swift_build_support/targets.py b/utils/swift_build_support/swift_build_support/targets.py index 6bc7abe319fb0..9370a1a82e0ee 100644 --- a/utils/swift_build_support/swift_build_support/targets.py +++ b/utils/swift_build_support/swift_build_support/targets.py @@ -179,6 +179,12 @@ class StdlibDeploymentTarget(object): sdk_name="WATCHOS_SIMULATOR", is_simulator=True) + # A platform that's not tied to any particular OS, and it meant to be used + # to build the stdlib as standalone and/or statically linked. + Freestanding = Platform("freestanding", + archs=["i386", "x86_64", "armv7", "armv7s", "armv7k", + "arm64", "arm64e"]) + Linux = Platform("linux", archs=[ "x86_64", "i686", @@ -207,6 +213,7 @@ class StdlibDeploymentTarget(object): iOS, iOSSimulator, AppleTV, AppleTVSimulator, AppleWatch, AppleWatchSimulator, + Freestanding, Linux, FreeBSD, OpenBSD, From 643aa2d8961c2f86b931658d026329adf00a35a9 Mon Sep 17 00:00:00 2001 From: Marcel Hlopko Date: Wed, 12 Aug 2020 16:54:22 +0200 Subject: [PATCH 092/663] [cxx-interop] Import `typedef`-ed template instantiations (#32950) In this PR we teach `ClangImporter` to import typedef statements with template instantiation as its underlying type. ```c++ template struct MagicWrapper { T t; }; struct MagicNumber {}; typedef MagicWrapper WrappedMagicNumber; ``` will be made available in Swift as if `WrappedMagicNumber` is a regular struct. In C++, multiple distinct typedeffed instantiations resolve to the same canonical type. We implement this by creating a hidden intermediate struct that typedef aliasses. The struct is named as `__CxxTemplateInst` plus Itanium mangled type of the instantiation. For the example above the name of the hidden struct is `__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Double underscore (denoting a reserved C++ identifier) is used to discourage direct usage. We chose Itanium mangling scheme because it produces valid Swift identifiers and covers all C++ edge cases. Imported module interface of the example above: ```swift struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { var t: MagicNumber } struct MagicNumber {} typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE ``` We modified the `SwiftLookupTable` logic to show hidden structs in `swift_ide_test` for convenience. Resolves https://bugs.swift.org/browse/SR-12591. Co-authored-by: Rosica Dejanovska Co-authored-by: Dmitri Gribenko Co-authored-by: Robert Widmann --- docs/ABI/Mangling.rst | 37 ++++++++++++++++ docs/CppInteroperabilityManifesto.md | 42 ++++++++++++++++++- include/swift/Strings.h | 4 ++ lib/AST/ASTMangler.cpp | 9 ++++ lib/ClangImporter/ImportDecl.cpp | 29 ++++++++++--- lib/ClangImporter/ImportName.cpp | 30 +++++++++++++ lib/ClangImporter/SwiftLookupTable.cpp | 23 +++++++++- .../Cxx/templates/Inputs/canonical-types.h | 18 ++++++++ .../decl-with-definition-including-members.h | 26 ++++++++++++ .../templates/Inputs/decl-with-definition.h | 24 +++++++++++ .../Inputs/decl-with-primitive-argument.h | 12 ++++++ .../Inputs/decl-without-definition.h | 20 +++++++++ .../Inputs/eager-instantiation-problems.h | 24 +++++++++++ .../Inputs/explicit-specialization.h | 29 +++++++++++++ ...kage-of-swift-symbols-for-imported-types.h | 21 ++++++++++ test/Interop/Cxx/templates/Inputs/mangling.h | 11 +++++ .../Cxx/templates/Inputs/module.modulemap | 39 +++++++++++++++++ .../Cxx/templates/Inputs/using-directive.h | 17 ++++++++ .../canonical-types-module-interface.swift | 15 +++++++ .../Cxx/templates/canonical-types.swift | 15 +++++++ ...cl-with-definition-including-members.swift | 16 +++++++ .../decl-with-definition-irgen.swift | 33 +++++++++++++++ .../decl-with-definition-silgen.swift | 21 ++++++++++ .../Cxx/templates/decl-with-definition.swift | 16 +++++++ .../decl-with-primitive-argument.swift | 15 +++++++ ...-without-definition-module-interface.swift | 15 +++++++ .../templates/decl-without-definition.swift | 16 +++++++ test/Interop/Cxx/templates/demangling.swift | 12 ++++++ .../eager-instatiation-problems.swift | 32 ++++++++++++++ .../templates/explicit-specialization.swift | 20 +++++++++ ...ift-symbols-for-imported-types-irgen.swift | 28 +++++++++++++ .../Cxx/templates/mangling-irgen.swift | 18 ++++++++ .../Cxx/templates/mangling-silgen.swift | 20 +++++++++ .../using-directive-module-interface.swift | 15 +++++++ .../Cxx/templates/using-directive.swift | 16 +++++++ test/lit.cfg | 2 + 36 files changed, 732 insertions(+), 8 deletions(-) create mode 100644 test/Interop/Cxx/templates/Inputs/canonical-types.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-definition.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-without-definition.h create mode 100644 test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h create mode 100644 test/Interop/Cxx/templates/Inputs/explicit-specialization.h create mode 100644 test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h create mode 100644 test/Interop/Cxx/templates/Inputs/mangling.h create mode 100644 test/Interop/Cxx/templates/Inputs/module.modulemap create mode 100644 test/Interop/Cxx/templates/Inputs/using-directive.h create mode 100644 test/Interop/Cxx/templates/canonical-types-module-interface.swift create mode 100644 test/Interop/Cxx/templates/canonical-types.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition-including-members.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition-irgen.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition-silgen.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition.swift create mode 100644 test/Interop/Cxx/templates/decl-with-primitive-argument.swift create mode 100644 test/Interop/Cxx/templates/decl-without-definition-module-interface.swift create mode 100644 test/Interop/Cxx/templates/decl-without-definition.swift create mode 100644 test/Interop/Cxx/templates/demangling.swift create mode 100644 test/Interop/Cxx/templates/eager-instatiation-problems.swift create mode 100644 test/Interop/Cxx/templates/explicit-specialization.swift create mode 100644 test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift create mode 100644 test/Interop/Cxx/templates/mangling-irgen.swift create mode 100644 test/Interop/Cxx/templates/mangling-silgen.swift create mode 100644 test/Interop/Cxx/templates/using-directive-module-interface.swift create mode 100644 test/Interop/Cxx/templates/using-directive.swift diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index a65799b8c53cd..f35339c9ebb70 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -1107,3 +1107,40 @@ nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` mo .. code:: sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct + +Importing C++ class template instantiations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A class template instantiation is imported as a struct named +``__CxxTemplateInst`` plus Itanium mangled type of the instantiation (see the +``type`` production in the Itanium specification). Note that Itanium mangling is +used on all platforms, regardless of the ABI of the C++ toolchain, to ensure +that the mangled name is a valid Swift type name (this is not the case for MSVC +mangled names). A prefix with a double underscore (to ensure we have a reserved +C++ identifier) is added to limit the possibility for conflicts with names of +user-defined structs. The struct is notionally defined in the ``__C`` module, +similarly to regular C and C++ structs and classes. Consider the following C++ +module: + +.. code-block:: c++ + + template + struct MagicWrapper { + T t; + }; + + struct MagicNumber {}; + + typedef MagicWrapper WrappedMagicNumber; + +``WrappedMagicNumber`` is imported as a typealias for struct +``__CxxTemplateInst12MagicWrapperI11MagicNumberE``. Interface of the imported +module looks as follows: + +.. code-block:: swift + + struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { + var t: MagicNumber + } + struct MagicNumber {} + typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE diff --git a/docs/CppInteroperabilityManifesto.md b/docs/CppInteroperabilityManifesto.md index f3a8df51820d2..b23c914268c1b 100644 --- a/docs/CppInteroperabilityManifesto.md +++ b/docs/CppInteroperabilityManifesto.md @@ -67,6 +67,7 @@ Assumptions: + [Function templates: calls with generic type parameters](#function-templates-calls-with-generic-type-parameters) + [Function templates: importing as real generic functions](#function-templates-importing-as-real-generic-functions) + [Class templates](#class-templates) + + [Class templates: importing instantiation behind typedef](#class-templates-importing-instantiation-behind-typedef) + [Class templates: importing specific specilalizations](#class-templates-importing-specific-specilalizations) + [Class templates: using with generic type parameters](#class-templates-using-with-generic-type-parameters) + [Class templates: using in generic code through a synthesized protocol](#class-templates-using-in-generic-code-through-a-synthesized-protocol) @@ -2575,6 +2576,45 @@ We could ignore explicit specializations of function templates, because they don't affect the API. Explicit specializations of class templates can dramatically change the API of the type. +### Class templates: Importing full class template instantiations + +A class template instantiation could be imported as a struct named +`__CxxTemplateInst` plus Itanium mangled type of the instantiation (see the +`type` production in the Itanium specification). Note that Itanium mangling is +used on all platforms, regardless of the ABI of the C++ toolchain, to ensure +that the mangled name is a valid Swift type name (this is not the case for MSVC +mangled names). A prefix with a double underscore (to ensure we have a reserved +C++ identifier) is added to limit the possibility for conflicts with names of +user-defined structs. The struct is notionally defined in the `__C` module, +similarly to regular C and C++ structs and classes. Consider the following C++ +module: + +```c++ +// C++ header. + +template +struct MagicWrapper { + T t; +}; +struct MagicNumber {}; + +typedef MagicWrapper WrappedMagicNumber; +``` + +`WrappedMagicNumber` will be imported as a typealias for a struct +`__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Interface of the imported +module will look as follows: + +```swift +// C++ header imported to Swift. + +struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { + var t: MagicNumber +} +struct MagicNumber {} +typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE +``` + ### Class templates: importing specific specilalizations Just like with calls to C++ function templates, it is easy to compile a use of a @@ -2752,7 +2792,7 @@ func useConcrete() { ### Class templates: importing as real generic structs -If we know the complete set of allowed type arguments to a C++ function +If we know the complete set of allowed type arguments to a C++ struct template, we could import it as an actual Swift generic struct. Every method of that struct will perform dynamic dispatch based on type parameters. See the section about function templates for more details. diff --git a/include/swift/Strings.h b/include/swift/Strings.h index 32a7bb2d0072c..69b29ff4a52b9 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -38,6 +38,10 @@ constexpr static const StringLiteral MANGLING_MODULE_OBJC = "__C"; constexpr static const StringLiteral MANGLING_MODULE_CLANG_IMPORTER = "__C_Synthesized"; +/// The name prefix for C++ template instantiation imported as a Swift struct. +constexpr static const StringLiteral CXX_TEMPLATE_INST_PREFIX = + "__CxxTemplateInst"; + constexpr static const StringLiteral SEMANTICS_PROGRAMTERMINATION_POINT = "programtermination_point"; diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index e013ad5db8b3c..be1c4af4e0ea1 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -39,6 +39,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" @@ -2114,6 +2115,7 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { // Always use Clang names for imported Clang declarations, unless they don't // have one. auto tryAppendClangName = [this, decl]() -> bool { + auto *nominal = dyn_cast(decl); auto namedDecl = getClangDeclForMangling(decl); if (!namedDecl) return false; @@ -2126,6 +2128,13 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { appendIdentifier(interface->getObjCRuntimeNameAsString()); } else if (UseObjCRuntimeNames && protocol) { appendIdentifier(protocol->getObjCRuntimeNameAsString()); + } else if (auto ctsd = dyn_cast(namedDecl)) { + // If this is a `ClassTemplateSpecializationDecl`, it was + // imported as a Swift decl with `__CxxTemplateInst...` name. + // `ClassTemplateSpecializationDecl`'s name does not include information about + // template arguments, and in order to prevent name clashes we use the + // name of the Swift decl which does include template arguments. + appendIdentifier(nominal->getName().str()); } else { appendIdentifier(namedDecl->getName()); } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e35b0aed470b7..b0ca58c4c4047 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3477,14 +3477,33 @@ namespace { Decl *VisitClassTemplateSpecializationDecl( const clang::ClassTemplateSpecializationDecl *decl) { - // FIXME: We could import specializations, but perhaps only as unnamed - // structural types. - return nullptr; + // `Sema::isCompleteType` will try to instantiate the class template as a + // side-effect and we rely on this here. `decl->getDefinition()` can + // return nullptr before the call to sema and return its definition + // afterwards. + if (!Impl.getClangSema().isCompleteType( + decl->getLocation(), + Impl.getClangASTContext().getRecordType(decl))) { + // If we got nullptr definition now it means the type is not complete. + // We don't import incomplete types. + return nullptr; + } + auto def = dyn_cast( + decl->getDefinition()); + assert(def && "Class template instantiation didn't have definition"); + // FIXME: This will instantiate all members of the specialization (and detect + // instantiation failures in them), which can be more than is necessary + // and is more than what Clang does. As a result we reject some C++ + // programs that Clang accepts. + Impl.getClangSema().InstantiateClassTemplateSpecializationMembers( + def->getLocation(), def, clang::TSK_ExplicitInstantiationDefinition); + + return VisitRecordDecl(def); } Decl *VisitClassTemplatePartialSpecializationDecl( - const clang::ClassTemplatePartialSpecializationDecl *decl) { - // Note: templates are not imported. + const clang::ClassTemplatePartialSpecializationDecl *decl) { + // Note: partial template specializations are not imported. return nullptr; } diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 1611d20507369..46817ce93de2a 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -31,8 +31,10 @@ #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Parser.h" +#include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Mangle.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" @@ -1698,6 +1700,34 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, } } + if (auto classTemplateSpecDecl = + dyn_cast(D)) { + if (!isa(D)) { + + auto &astContext = classTemplateSpecDecl->getASTContext(); + // Itanium mangler produces valid Swift identifiers, use it to generate a name for + // this instantiation. + clang::MangleContext *mangler = clang::ItaniumMangleContext::create( + astContext, astContext.getDiagnostics()); + llvm::SmallString<128> storage; + llvm::raw_svector_ostream buffer(storage); + mangler->mangleTypeName(astContext.getRecordType(classTemplateSpecDecl), + buffer); + + // The Itanium mangler does not provide a way to get the mangled + // representation of a type. Instead, we call mangleTypeName() that + // returns the name of the RTTI typeinfo symbol, and remove the _ZTS + // prefix. Then we prepend __CxxTemplateInst to reduce chances of conflict + // with regular C and C++ structs. + llvm::SmallString<128> mangledNameStorage; + llvm::raw_svector_ostream mangledName(mangledNameStorage); + assert(buffer.str().take_front(4) == "_ZTS"); + mangledName << CXX_TEMPLATE_INST_PREFIX << buffer.str().drop_front(4); + + baseName = swiftCtx.getIdentifier(mangledName.str()).get(); + } + } + // swift_newtype-ed declarations may have common words with the type name // stripped. if (auto newtypeDecl = findSwiftNewtype(D, clangSema, version)) { diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 74a64dcb025d5..3ac0d0fe45d0c 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1881,10 +1881,16 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table, // struct names when relevant, not just pointer names. That way we can check // both CFDatabase.def and the objc_bridge attribute and cover all our bases. if (auto *tagDecl = dyn_cast(named)) { - if (!tagDecl->getDefinition()) + // We add entries for ClassTemplateSpecializations that don't have + // definition. It's possible that the decl will be instantiated by + // SwiftDeclConverter later on. We cannot force instantiating + // ClassTemplateSPecializations here because we're currently writing the + // AST, so we cannot modify it. + if (!isa(named) && + !tagDecl->getDefinition()) { return; + } } - // If we have a name to import as, add this entry to the table. auto currentVersion = ImportNameVersion::fromOptions(nameImporter.getLangOpts()); @@ -2077,6 +2083,19 @@ void SwiftLookupTableWriter::populateTableWithDecl(SwiftLookupTable &table, // Add this entry to the lookup table. addEntryToLookupTable(table, named, nameImporter); + if (auto typedefDecl = dyn_cast(named)) { + if (auto typedefType = dyn_cast( + typedefDecl->getUnderlyingType())) { + if (auto CTSD = dyn_cast( + typedefType->getAsTagDecl())) { + // Adding template instantiation behind typedef as a top-level entry + // so the instantiation appears in the API. + assert(!isa(CTSD) && + "Class template partial specialization cannot appear behind typedef"); + addEntryToLookupTable(table, CTSD, nameImporter); + } + } + } } void SwiftLookupTableWriter::populateTable(SwiftLookupTable &table, diff --git a/test/Interop/Cxx/templates/Inputs/canonical-types.h b/test/Interop/Cxx/templates/Inputs/canonical-types.h new file mode 100644 index 0000000000000..865c85a882cf9 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/canonical-types.h @@ -0,0 +1,18 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +typedef MagicWrapper WrappedMagicNumberA; +typedef MagicWrapper WrappedMagicNumberB; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h new file mode 100644 index 0000000000000..4c772c9dfaca0 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h @@ -0,0 +1,26 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +inline int forceInstantiation() { + auto t = MagicWrapper(); + return t.getValuePlusArg(14); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition +// because function above forced the instantiation. Its members are fully +// instantiated, so nothing needs to be explicitly instantiated by the Swift +// compiler. +typedef MagicWrapper FullyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h new file mode 100644 index 0000000000000..d8fb7b56f676b --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h @@ -0,0 +1,24 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +inline MagicWrapper forceInstantiation() { + return MagicWrapper(); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition +// because function above forced the instantiation. Its members are not +// instantiated though, the Swift compiler needs to instantiate them. +typedef MagicWrapper PartiallyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h new file mode 100644 index 0000000000000..2bba7d493e342 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h @@ -0,0 +1,12 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t + arg; } +}; + +typedef MagicWrapper WrappedMagicInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-without-definition.h b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h new file mode 100644 index 0000000000000..a4eb3506672b2 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h @@ -0,0 +1,20 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +// The ClassTemplateSpecializationDecl node for MagicWrapper doesn't have a +// definition in Clang because nothing in this header required the +// instantiation. Therefore, the Swift compiler must trigger instantiation. +typedef MagicWrapper MagicallyWrappedIntWithoutDefinition; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h new file mode 100644 index 0000000000000..5992054ae9d3d --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h @@ -0,0 +1,24 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H + +struct MagicNumber { + int getInt() const { return 42; } +}; + +template +struct MagicWrapper { + void callGetInt() const { + T::getIntDoesNotExist(); + } + + template int sfinaeGetInt(A a, decltype(&A::getInt)) { + return a.getInt(); + } + template int sfinaeGetInt(A a, ...) { + return -42; + } +}; + +typedef MagicWrapper BrokenMagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H diff --git a/test/Interop/Cxx/templates/Inputs/explicit-specialization.h b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h new file mode 100644 index 0000000000000..62b9f7aa030af --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h @@ -0,0 +1,29 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H + +struct SpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +struct NonSpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +template +struct MagicWrapper { + T t; + int doubleIfSpecializedElseTriple() const { return 3 * t.getValue(); } +}; + +template <> +struct MagicWrapper { + SpecializedIntWrapper t; + int doubleIfSpecializedElseTriple() const { return 2 * t.getValue(); } +}; + +typedef MagicWrapper WrapperWithSpecialization; +typedef MagicWrapper WrapperWithoutSpecialization; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H diff --git a/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h new file mode 100644 index 0000000000000..d700209d93873 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h @@ -0,0 +1,21 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H + +template +struct MagicWrapper { + T t; + int callGetInt() const { + return t.getInt() + 5; + } +}; + +struct MagicNumber { + // Swift runtime defines many value witness tables for types with some common layouts. + // This struct's uncommon size forces the compiler to define a new value witness table instead of reusing one from the runtime. + char forceVWTableCreation[57]; + int getInt() const { return 12; } +}; + +typedef MagicWrapper WrappedMagicNumber; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/mangling.h b/test/Interop/Cxx/templates/Inputs/mangling.h new file mode 100644 index 0000000000000..f135b52747600 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/mangling.h @@ -0,0 +1,11 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H + +template +struct MagicWrapper {}; + +typedef MagicWrapper WrappedMagicInt; +typedef MagicWrapper WrappedMagicBool; + + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H diff --git a/test/Interop/Cxx/templates/Inputs/module.modulemap b/test/Interop/Cxx/templates/Inputs/module.modulemap new file mode 100644 index 0000000000000..af6d28e675a40 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/module.modulemap @@ -0,0 +1,39 @@ +module DeclWithPrimitiveArgument { + header "decl-with-primitive-argument.h" +} + +module DeclWithoutDefinition { + header "decl-without-definition.h" +} + +module DeclWithDefinition { + header "decl-with-definition.h" +} + +module DeclWithDefinitionIncludingMembers { + header "decl-with-definition-including-members.h" +} + +module CanonicalTypes { + header "canonical-types.h" +} + +module ExplicitSpecialization { + header "explicit-specialization.h" +} + +module UsingDirective { + header "using-directive.h" +} + +module EagerInstantiationProblems { + header "eager-instantiation-problems.h" +} + +module Mangling { + header "mangling.h" +} + +module LinkageOfSwiftSymbolsForImportedTypes { + header "linkage-of-swift-symbols-for-imported-types.h" +} diff --git a/test/Interop/Cxx/templates/Inputs/using-directive.h b/test/Interop/Cxx/templates/Inputs/using-directive.h new file mode 100644 index 0000000000000..076660e8a19e4 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/using-directive.h @@ -0,0 +1,17 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +using UsingWrappedMagicNumber = MagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H diff --git a/test/Interop/Cxx/templates/canonical-types-module-interface.swift b/test/Interop/Cxx/templates/canonical-types-module-interface.swift new file mode 100644 index 0000000000000..3a90d1d44311a --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=CanonicalTypes -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias WrappedMagicNumberA = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK: typealias WrappedMagicNumberB = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/canonical-types.swift b/test/Interop/Cxx/templates/canonical-types.swift new file mode 100644 index 0000000000000..b399e0fc9b144 --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import CanonicalTypes +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("canonical-types") { + // Different typedefs with the same C++ canonical type must have the same type from Swift's perspective as well. + expectEqualType(WrappedMagicNumberA.self, WrappedMagicNumberB.self) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-including-members.swift b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift new file mode 100644 index 0000000000000..7d55595d4fbb4 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithDefinitionIncludingMembers +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("fully-defined") { + let myInt = IntWrapper(value: 10) + var magicInt = FullyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 15) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift new file mode 100644 index 0000000000000..34825a34ce7e4 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift @@ -0,0 +1,33 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 7) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(13) +} + +// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main18getWrappedMagicInts5Int32VyF"() +// CHECK: %magicInt = alloca %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, align 4 +// CHECK: %magicInt.t = getelementptr inbounds %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt, i32 0, i32 0 +// CHECK: [[MAGIC_WRAPPER:%.*]] = bitcast %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt to %struct.MagicWrapper* +// CHECK: call i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* [[MAGIC_WRAPPER]], i32 13) + +// CHECK: define weak_odr{{( dso_local)?}} i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* %this, i32 %arg) +// CHECK: %this.addr = alloca %struct.MagicWrapper*, align {{4|8}} +// CHECK: store %struct.MagicWrapper* %this, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.MagicWrapper*, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %t = getelementptr inbounds %struct.MagicWrapper, %struct.MagicWrapper* %this1, i32 0, i32 0 +// CHECK: %call = call i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %t) +// CHECK: [[ARG:%.*]] = load i32, i32* %arg.addr, align 4 +// CHECK: %add = add nsw i32 %call, [[ARG]] +// CHECK: ret i32 %add + +// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %this) +// CHECK: %this.addr = alloca %struct.IntWrapper*, align {{4|8}} +// CHECK: store %struct.IntWrapper* %this, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.IntWrapper*, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %value = getelementptr inbounds %struct.IntWrapper, %struct.IntWrapper* %this1, i32 0, i32 0 +// CHECK: [[VALUE:%.*]] = load i32, i32* %value, align 4 +// CHECK: ret i32 [[VALUE]] diff --git a/test/Interop/Cxx/templates/decl-with-definition-silgen.swift b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift new file mode 100644 index 0000000000000..a9481f6ac9d6c --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift @@ -0,0 +1,21 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 21) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(32) +} + +// CHECK: // getWrappedMagicInt() +// CHECK: sil @$s4main18getWrappedMagicInts5Int32VyF : $@convention(thin) () -> Int32 { +// CHECK: [[INT_WRAPPER:%.*]] = struct $IntWrapper ([[_:%.*]] : $Int32) +// CHECK: [[_:%.*]] = struct $__CxxTemplateInst12MagicWrapperI10IntWrapperE ([[INT_WRAPPER]] : $IntWrapper) +// CHECK: // function_ref {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: [[_:%.*]] = function_ref @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 + +// CHECK: // {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: MagicWrapper::getValuePlusArg + +// CHECK: sil [clang __CxxTemplateInst12MagicWrapperI10IntWrapperE.getValuePlusArg] @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 diff --git a/test/Interop/Cxx/templates/decl-with-definition.swift b/test/Interop/Cxx/templates/decl-with-definition.swift new file mode 100644 index 0000000000000..ce0841c4b9c9b --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("has-partial-definition") { + let myInt = IntWrapper(value: 32) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 37) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-primitive-argument.swift b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift new file mode 100644 index 0000000000000..a2d5d1f8c9b98 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithPrimitiveArgument +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("int-argument") { + var wrappedMagicInt = WrappedMagicInt(t: 42) + expectEqual(wrappedMagicInt.getValuePlusArg(5), 47) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift new file mode 100644 index 0000000000000..ca12841f96cb9 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=DeclWithoutDefinition -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias MagicallyWrappedIntWithoutDefinition = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/decl-without-definition.swift b/test/Interop/Cxx/templates/decl-without-definition.swift new file mode 100644 index 0000000000000..ef97376176ed4 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithoutDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("without-definition") { + let myInt = IntWrapper(value: 17) + var magicInt = MagicallyWrappedIntWithoutDefinition(t: myInt) + expectEqual(magicInt.getValuePlusArg(11), 28) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/demangling.swift b/test/Interop/Cxx/templates/demangling.swift new file mode 100644 index 0000000000000..ac1e44efefe83 --- /dev/null +++ b/test/Interop/Cxx/templates/demangling.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | grep 'define.*swiftcc.*$' | grep -o '\$[[:alnum:]]\+__CxxTemplateInst[[:alnum:]]\+' | xargs %swift-demangle | %FileCheck %s + +import Mangling + +public func receiveInstantiation(_ i: inout WrappedMagicInt) {} + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: $s10demangling20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF ---> demangling.receiveInstantiation(inout __C.__CxxTemplateInst12MagicWrapperIiE) -> () +// CHECK: $s10demangling19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF ---> demangling.returnInstantiation() -> __C.__CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/eager-instatiation-problems.swift b/test/Interop/Cxx/templates/eager-instatiation-problems.swift new file mode 100644 index 0000000000000..b2520b5b78275 --- /dev/null +++ b/test/Interop/Cxx/templates/eager-instatiation-problems.swift @@ -0,0 +1,32 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import EagerInstantiationProblems +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("eager-instantiation-of-members") { + // This will fail with: + // + // error: type 'int' cannot be used prior to '::' because it has no members + // T::getIntDoesNotExist(); + // + // whereas in C++ this compiles. This is caused by ClangImporter eagerly + // instantiating typedeffed templates and also their members. + // TODO(scentini): Fix this + // let _brokenMagicWrapper = BrokenMagicWrapper() +} + +TemplatesTestSuite.test("sfinae-example") { + // This will fail since we are currently not instantiating function templates. + // In C++ the first sfinaeGetInt should fail to instantiate, therefore get + // ignored, and only the second sfinaeGetInt is used. + // TODO(SR-12541): Fix this + // let magicNumber = MagicNumber() + // var brokenMagicWrapper = BrokenMagicWrapper() + // expectEqual(42, brokenMagicWrapper.sfinaeGetInt(magicNumber, 0)) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/explicit-specialization.swift b/test/Interop/Cxx/templates/explicit-specialization.swift new file mode 100644 index 0000000000000..58cb0c4d6746d --- /dev/null +++ b/test/Interop/Cxx/templates/explicit-specialization.swift @@ -0,0 +1,20 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import ExplicitSpecialization +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("explicit-specialization") { + let specializedInt = SpecializedIntWrapper(value: 7) + var specializedMagicInt = WrapperWithSpecialization(t: specializedInt) + expectEqual(specializedMagicInt.doubleIfSpecializedElseTriple(), 14) + + let nonSpecializedInt = NonSpecializedIntWrapper(value: 7) + var nonSpecializedMagicInt = WrapperWithoutSpecialization(t: nonSpecializedInt) + expectEqual(nonSpecializedMagicInt.doubleIfSpecializedElseTriple(), 21) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift new file mode 100644 index 0000000000000..f3a2ae75d69ba --- /dev/null +++ b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift @@ -0,0 +1,28 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import LinkageOfSwiftSymbolsForImportedTypes + +public func forceValueWitnessTableCreation() -> Any { + let magicNumber = MagicNumber() + return WrappedMagicNumber(t: magicNumber) +} + +public func getMagicNumberForLinkageComparison() -> Any { + return MagicNumber() +} + +// CHECK: $sSo11MagicNumberVWV" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMn" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMf" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVML" = linkonce_odr hidden global + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVWV" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMn" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMf" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVML" = linkonce_odr hidden global + +// CHECK: $sSo11MagicNumberVMB" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMF" = linkonce_odr hidden constant + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMB" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMF" = linkonce_odr hidden constant diff --git a/test/Interop/Cxx/templates/mangling-irgen.swift b/test/Interop/Cxx/templates/mangling-irgen.swift new file mode 100644 index 0000000000000..363e1a3e76800 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-irgen.swift @@ -0,0 +1,18 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func receiveInstantiation(_ i: inout WrappedMagicInt) {} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIiEV* nocapture dereferenceable(1) %0) + +public func receiveInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIbEV* nocapture dereferenceable(1) %0) + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF"() + diff --git a/test/Interop/Cxx/templates/mangling-silgen.swift b/test/Interop/Cxx/templates/mangling-silgen.swift new file mode 100644 index 0000000000000..7d4cc6f7e3c39 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-silgen.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func recvInstantiation(_ i: inout WrappedMagicInt) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIiE) -> () + +public func recvInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIbE) -> () + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: // returnInstantiation() +// CHECK: sil @$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF : $@convention(thin) () -> __CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/using-directive-module-interface.swift b/test/Interop/Cxx/templates/using-directive-module-interface.swift new file mode 100644 index 0000000000000..81b445d21e3d7 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=UsingDirective -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias UsingWrappedMagicNumber = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/using-directive.swift b/test/Interop/Cxx/templates/using-directive.swift new file mode 100644 index 0000000000000..7f9c983fee834 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import StdlibUnittest +import UsingDirective + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("using-directive") { + let myInt = IntWrapper(value: 333) + var magicInt = UsingWrappedMagicNumber(t: myInt) + expectEqual(magicInt.getValuePlusArg(111), 444) +} + +runAllTests() diff --git a/test/lit.cfg b/test/lit.cfg index e8a4a36443fbf..27c40a1cb6764 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -282,6 +282,7 @@ config.sourcekitd_test = inferSwiftBinary('sourcekitd-test') config.complete_test = inferSwiftBinary('complete-test') config.swift_api_digester = inferSwiftBinary('swift-api-digester') config.swift_refactor = inferSwiftBinary('swift-refactor') +config.swift_demangle = inferSwiftBinary('swift-demangle') config.swift_demangle_yamldump = inferSwiftBinary('swift-demangle-yamldump') config.benchmark_o = inferSwiftBinary('Benchmark_O') config.benchmark_driver = inferSwiftBinary('Benchmark_Driver') @@ -439,6 +440,7 @@ config.substitutions.append( ('%llvm-dwarfdump', config.llvm_dwarfdump) ) config.substitutions.append( ('%llvm-readelf', config.llvm_readelf) ) config.substitutions.append( ('%llvm-dis', config.llvm_dis) ) config.substitutions.append( ('%llvm-nm', config.llvm_nm) ) +config.substitutions.append( ('%swift-demangle', config.swift_demangle) ) config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_yamldump) ) config.substitutions.append( ('%Benchmark_O', config.benchmark_o) ) config.substitutions.append( ('%Benchmark_Driver', config.benchmark_driver) ) From 40c1687fd25ae2e26ad0f98a0704dd0d8240edef Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 12 Aug 2020 10:12:35 -0700 Subject: [PATCH 093/663] [Fast Dependency Scanner] Produce information on whether an explicit module is a framework In the fast dependency scanner, depending on whether a module intrface was found via the import search path or framework search path, encode into the dependency graph Swift module details, whether a given module is a framework. --- include/swift/AST/ModuleDependencies.h | 19 +++++++++------ .../swift/Frontend/ModuleInterfaceLoader.h | 16 +++++++------ .../Serialization/SerializedModuleLoader.h | 9 +++++--- lib/Frontend/ModuleInterfaceLoader.cpp | 6 +++-- lib/FrontendTool/ScanDependencies.cpp | 12 ++++++++++ lib/Serialization/ModuleDependencyScanner.cpp | 16 ++++++++----- lib/Serialization/SerializedModuleLoader.cpp | 19 ++++++++------- .../Inputs/ModuleDependencyGraph.swift | 3 +++ .../can_import_with_map.swift | 9 +++++--- ...xplicit-module-map-forwarding-module.swift | 9 +++++--- .../explicit-module-map.swift | 9 +++++--- .../module_deps_external.swift | 17 +++++--------- test/ScanDependencies/module_framework.swift | 23 +++++++++++++++++++ test/ScanDependencies/module_not_found.swift | 2 ++ unittests/FrontendTool/ModuleLoadingTests.cpp | 2 +- 15 files changed, 117 insertions(+), 54 deletions(-) create mode 100644 test/ScanDependencies/module_framework.swift diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 44cceb47af7ba..766e8840279e5 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -107,6 +107,9 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase { /// The hash value that will be used for the generated module const std::string contextHash; + /// A flag that indicates this dependency is a framework + const bool isFramework; + /// Bridging header file, if there is one. Optional bridgingHeaderFile; @@ -125,7 +128,8 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase { ArrayRef compiledModuleCandidates, ArrayRef buildCommandLine, ArrayRef extraPCMArgs, - StringRef contextHash + StringRef contextHash, + bool isFramework = false ) : ModuleDependenciesStorageBase(ModuleDependenciesKind::Swift, compiledModulePath), swiftInterfaceFile(swiftInterfaceFile), @@ -133,7 +137,7 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase { compiledModuleCandidates.end()), buildCommandLine(buildCommandLine.begin(), buildCommandLine.end()), extraPCMArgs(extraPCMArgs.begin(), extraPCMArgs.end()), - contextHash(contextHash) { } + contextHash(contextHash), isFramework(isFramework) { } ModuleDependenciesStorageBase *clone() const override { return new SwiftModuleDependenciesStorage(*this); @@ -242,21 +246,22 @@ class ModuleDependencies { ArrayRef compiledCandidates, ArrayRef buildCommands, ArrayRef extraPCMArgs, - StringRef contextHash) { + StringRef contextHash, + bool isFramework) { std::string compiledModulePath; return ModuleDependencies( std::make_unique( compiledModulePath, swiftInterfaceFile, compiledCandidates, buildCommands, - extraPCMArgs, contextHash)); + extraPCMArgs, contextHash, isFramework)); } /// Describe the module dependencies for a serialized or parsed Swift module. static ModuleDependencies forSwiftModule( - const std::string &compiledModulePath) { + const std::string &compiledModulePath, bool isFramework) { return ModuleDependencies( std::make_unique( compiledModulePath, None, ArrayRef(), ArrayRef(), - ArrayRef(), StringRef())); + ArrayRef(), StringRef(), isFramework)); } /// Describe the main Swift module. @@ -265,7 +270,7 @@ class ModuleDependencies { return ModuleDependencies( std::make_unique( compiledModulePath, None, ArrayRef(), - ArrayRef(), extraPCMArgs, StringRef())); + ArrayRef(), extraPCMArgs, StringRef(), false)); } /// Describe the module dependencies for a Clang module that can be diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 78116f109a8e8..3eac993f14f61 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -139,7 +139,8 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool canImportModule(Located mID) override; @@ -298,12 +299,13 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase { ModuleInterfaceLoaderOptions Opts; std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool isCached(StringRef DepPath) override; public: diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index ec2ad4a8a29ab..ab6c5cbb96ab1 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -98,7 +98,8 @@ class SerializedModuleLoaderBase : public ModuleLoader { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) = 0; + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) = 0; std::error_code openModuleFile( @@ -229,7 +230,8 @@ class ImplicitSerializedModuleLoader : public SerializedModuleLoaderBase { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, @@ -274,7 +276,8 @@ class MemoryBufferSerializedModuleLoader : public SerializedModuleLoaderBase { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override; + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index fed69f9a43f13..27cbdd7ee8b22 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -950,7 +950,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { // If running in OnlySerialized mode, ModuleInterfaceLoader // should not have been constructed at all. @@ -1527,7 +1528,8 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { StringRef moduleName = ModuleID.Item.str(); auto it = Impl.ExplicitModuleMap.find(moduleName); // If no explicit module path is given matches the name, return with an diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 6a90ae8231c86..df2829276e526 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -216,6 +216,13 @@ namespace { out << "\""; } + /// Write a boolean value as JSON. + void writeJSONValue(llvm::raw_ostream &out, + bool value, + unsigned indentLevel) { + out.write_escaped(value ? "true" : "false"); + } + /// Write a module identifier. void writeJSONValue(llvm::raw_ostream &out, const ModuleDependencyID &module, @@ -397,6 +404,11 @@ static void writeJSON(llvm::raw_ostream &out, swiftDeps->compiledModulePath, 5, /*trailingComma=*/false); } + writeJSONSingleField( + out, "isFramework", + swiftDeps->isFramework, 5, + /*trailingComma=*/!swiftDeps->extraPCMArgs.empty() || + swiftDeps->bridgingHeaderFile.hasValue()); if (!swiftDeps->extraPCMArgs.empty()) { out.indent(5 * 2); out << "\"extraPcmArgs\": [\n"; diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index c0d4b8ce4b931..d72577a2741b6 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -34,7 +34,7 @@ class ModuleDependencyScanner : public SerializedModuleLoaderBase { /// Scan the given interface file to determine dependencies. ErrorOr scanInterfaceFile( - Twine moduleInterfacePath); + Twine moduleInterfacePath, bool isFramework); InterfaceSubContextDelegate &astDelegate; public: @@ -58,7 +58,8 @@ class ModuleDependencyScanner : public SerializedModuleLoaderBase { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override { using namespace llvm::sys; auto &fs = *Ctx.SourceMgr.getFileSystem(); @@ -80,7 +81,7 @@ class ModuleDependencyScanner : public SerializedModuleLoaderBase { } } assert(fs.exists(InPath)); - auto dependencies = scanInterfaceFile(InPath); + auto dependencies = scanInterfaceFile(InPath, IsFramework); if (dependencies) { this->dependencies = std::move(dependencies.get()); return std::error_code(); @@ -142,7 +143,8 @@ class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner { SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) override { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override { StringRef moduleName = ModuleID.Item.str(); auto it = PlaceholderDependencyModuleMap.find(moduleName); // If no placeholder module stub path is given matches the name, return with an @@ -172,7 +174,7 @@ static std::vector getCompiledCandidates(ASTContext &ctx, } ErrorOr ModuleDependencyScanner::scanInterfaceFile( - Twine moduleInterfacePath) { + Twine moduleInterfacePath, bool isFramework) { // Create a module filename. // FIXME: Query the module interface loader to determine an appropriate // name for the module, which includes an appropriate hash. @@ -181,6 +183,7 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( llvm::sys::path::replace_extension(modulePath, newExt); Optional Result; std::error_code code; + auto hasError = astDelegate.runInSubContext(moduleName.str(), moduleInterfacePath.str(), StringRef(), @@ -196,7 +199,8 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( compiledCandidates, Args, PCMArgs, - Hash); + Hash, + isFramework); // Open the interface file. auto &fs = *Ctx.SourceMgr.getFileSystem(); auto interfaceBuf = fs.getBufferForFile(moduleInterfacePath); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 77d0a0a2154a0..57cad1cdc009c 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -396,7 +396,7 @@ llvm::ErrorOr SerializedModuleLoaderBase::scanModuleFile( &extInfo); // Map the set of dependencies over to the "module dependencies". - auto dependencies = ModuleDependencies::forSwiftModule(modulePath.str()); + auto dependencies = ModuleDependencies::forSwiftModule(modulePath.str(), isFramework); llvm::StringSet<> addedModuleNames; for (const auto &dependency : loadedModuleFile->getDependencies()) { // FIXME: Record header dependency? @@ -422,7 +422,8 @@ std::error_code ImplicitSerializedModuleLoader::findModuleFilesInDirectory( SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { assert(((ModuleBuffer && ModuleDocBuffer) || (!ModuleBuffer && !ModuleDocBuffer)) && "Module and Module Doc buffer must both be initialized or NULL"); @@ -538,7 +539,7 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, /// Returns true if a target-specific module file was found, false if an error /// was diagnosed, or None if neither one happened and the search should /// continue. - auto findTargetSpecificModuleFiles = [&]() -> Optional { + auto findTargetSpecificModuleFiles = [&](bool IsFramework) -> Optional { Optional firstAbsoluteBaseName; for (const auto &targetSpecificBaseName : targetSpecificBaseNames) { @@ -552,7 +553,8 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, absoluteBaseName, moduleInterfacePath, moduleBuffer, moduleDocBuffer, - moduleSourceInfoBuffer); + moduleSourceInfoBuffer, + IsFramework); if (!result) { return true; } else if (result == std::errc::not_supported) { @@ -603,13 +605,13 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, if (checkTargetSpecificModule) // A .swiftmodule directory contains architecture-specific files. - return findTargetSpecificModuleFiles(); + return findTargetSpecificModuleFiles(isFramework); SerializedModuleBaseName absoluteBaseName{currPath, genericBaseName}; auto result = findModuleFilesInDirectory( moduleID, absoluteBaseName, moduleInterfacePath, - moduleBuffer, moduleDocBuffer, moduleSourceInfoBuffer); + moduleBuffer, moduleDocBuffer, moduleSourceInfoBuffer, isFramework); if (!result) return true; else if (result == std::errc::not_supported) @@ -628,7 +630,7 @@ SerializedModuleLoaderBase::findModule(AccessPathElem moduleID, // Frameworks always use architecture-specific files within a // .swiftmodule directory. llvm::sys::path::append(currPath, "Modules"); - return findTargetSpecificModuleFiles(); + return findTargetSpecificModuleFiles(isFramework); } } llvm_unreachable("covered switch"); @@ -1081,7 +1083,8 @@ std::error_code MemoryBufferSerializedModuleLoader::findModuleFilesInDirectory( SmallVectorImpl *ModuleInterfacePath, std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer) { + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { // This is a soft error instead of an llvm_unreachable because this API is // primarily used by LLDB which makes it more likely that unwitting changes to // the Swift compiler accidentally break the contract. diff --git a/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift b/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift index 464afba79f014..4c84230cd4efb 100644 --- a/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift +++ b/test/ScanDependencies/Inputs/ModuleDependencyGraph.swift @@ -90,6 +90,9 @@ struct SwiftModuleDetails: Codable { /// arguments to the generic PCM build arguments reported from the dependency /// graph. var extraPcmArgs: [String]? + + /// A flag to indicate whether or not this module is a framework. + var isFramework: Bool } /// Details specific to Swift external modules. diff --git a/test/ScanDependencies/can_import_with_map.swift b/test/ScanDependencies/can_import_with_map.swift index e21bf826fe038..3becb8115eb1f 100644 --- a/test/ScanDependencies/can_import_with_map.swift +++ b/test/ScanDependencies/can_import_with_map.swift @@ -8,15 +8,18 @@ // RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/Foo.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-frontend -typecheck %s -explicit-swift-module-map-file %t/inputs/map.json -disable-implicit-swift-modules diff --git a/test/ScanDependencies/explicit-module-map-forwarding-module.swift b/test/ScanDependencies/explicit-module-map-forwarding-module.swift index 5d3c3cfa82c60..c8b694cea201c 100644 --- a/test/ScanDependencies/explicit-module-map-forwarding-module.swift +++ b/test/ScanDependencies/explicit-module-map-forwarding-module.swift @@ -18,15 +18,18 @@ // RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/Foo-from-interface.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-ide-test -print-module-comments -module-to-print=Foo -enable-swiftsourceinfo -source-filename %s -explicit-swift-module-map-file %t/inputs/map.json | %FileCheck %s diff --git a/test/ScanDependencies/explicit-module-map.swift b/test/ScanDependencies/explicit-module-map.swift index 821a6cfdc847f..77bfe5dd248f6 100644 --- a/test/ScanDependencies/explicit-module-map.swift +++ b/test/ScanDependencies/explicit-module-map.swift @@ -9,15 +9,18 @@ // RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/Foo.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-ide-test -print-module-comments -module-to-print=Foo -enable-swiftsourceinfo -source-filename %s -explicit-swift-module-map-file %t/inputs/map.json | %FileCheck %s diff --git a/test/ScanDependencies/module_deps_external.swift b/test/ScanDependencies/module_deps_external.swift index 601b60d62b4e7..c7eb47a7f4e87 100644 --- a/test/ScanDependencies/module_deps_external.swift +++ b/test/ScanDependencies/module_deps_external.swift @@ -6,23 +6,18 @@ // RUN: echo "\"moduleName\": \"SomeExternalModule\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%/t/inputs/SomeExternalModule.swiftmodule\"," >> %/t/inputs/map.json // RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"" >> %/t/inputs/map.json -// RUN: echo "}]" >> %/t/inputs/map.json - - -// RUN: echo "[{" > %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"SomeExternalModule\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/t/inputs/SomeExternalModule.swiftmodule\"," >> %/t/inputs/map.json -// RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json -// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"" >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules diff --git a/test/ScanDependencies/module_framework.swift b/test/ScanDependencies/module_framework.swift new file mode 100644 index 0000000000000..a6b0dfdeaa291 --- /dev/null +++ b/test/ScanDependencies/module_framework.swift @@ -0,0 +1,23 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json +// REQUIRES: objc_interop + +import CryptoKit + +// CHECK: "mainModuleName": "deps" +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "CryptoKit" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "Swift" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "SwiftOnoneSupport" +// CHECK-NEXT: } +// CHECK-NEXT: ], + +// CHECK: "isFramework": true diff --git a/test/ScanDependencies/module_not_found.swift b/test/ScanDependencies/module_not_found.swift index 1674f380b3732..8fd238eba6736 100644 --- a/test/ScanDependencies/module_not_found.swift +++ b/test/ScanDependencies/module_not_found.swift @@ -7,10 +7,12 @@ // RUN: echo "[{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%stdlib_dir/Swift.swiftmodule/%module-target-triple.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}," >> %/t/inputs/map.json // RUN: echo "{" >> %/t/inputs/map.json // RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json // RUN: echo "\"modulePath\": \"%stdlib_dir/SwiftOnoneSupport.swiftmodule/%module-target-triple.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // Add the -I search path to ensure we do not accidentally implicitly load Foo.swiftmodule diff --git a/unittests/FrontendTool/ModuleLoadingTests.cpp b/unittests/FrontendTool/ModuleLoadingTests.cpp index 7e343aaeeeab1..7185ffed81ded 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -116,7 +116,7 @@ class ModuleInterfaceLoaderTest : public testing::Test { loader->findModuleFilesInDirectory({moduleName, SourceLoc()}, SerializedModuleBaseName(tempDir, SerializedModuleBaseName("Library")), /*ModuleInterfacePath*/nullptr, - &moduleBuffer, &moduleDocBuffer, &moduleSourceInfoBuffer); + &moduleBuffer, &moduleDocBuffer, &moduleSourceInfoBuffer, /*IsFramework*/false); ASSERT_FALSE(error); ASSERT_FALSE(diags.hadAnyError()); From 7e714c5839ab533db3766efc071f266afa4bada1 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 5 Aug 2020 20:09:24 -0300 Subject: [PATCH 094/663] Fix reading metadata from ELF sections (cherry picked from commit 7cd920403d2005df6d18ff7c9c545467a2568577) --- include/swift/Reflection/ReflectionContext.h | 170 ++++++++++++++----- 1 file changed, 124 insertions(+), 46 deletions(-) diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 06cc0dab587b5..c3818f477eaf6 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -22,6 +22,7 @@ #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/Memory.h" #include "swift/ABI/Enum.h" #include "swift/ABI/ObjectFile.h" @@ -393,29 +394,60 @@ class ReflectionContext return readPECOFFSections(ImageStart); } - template bool readELFSections(RemoteAddress ImageStart) { - auto Buf = - this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); + template + bool readELFSections(RemoteAddress ImageStart, + llvm::Optional FileBuffer) { + // When reading from the FileBuffer we can simply return a pointer to + // the underlying data. + // When reading from the process, we need to keep the memory around + // until the end of the function, so we store it inside ReadDataBuffer. + // We do this so in both cases we can return a simple pointer. + std::vector ReadDataBuffer; + auto readData = [&](uint64_t Offset, uint64_t Size) -> const void * { + if (FileBuffer.hasValue()) { + auto Buffer = FileBuffer.getValue(); + if (Offset + Size > Buffer.allocatedSize()) + return nullptr; + return (const void *)((uint64_t)Buffer.base() + Offset); + } else { + MemoryReader::ReadBytesResult Buf = + this->getReader().readBytes(ImageStart + Offset, Size); + if (!Buf) + return nullptr; + ReadDataBuffer.push_back(std::move(Buf)); + return ReadDataBuffer.back().get(); + } + }; - auto Hdr = reinterpret_cast(Buf.get()); + const void *Buf = readData(0, sizeof(typename T::Header)); + if (!Buf) + return false; + auto Hdr = reinterpret_cast(Buf); assert(Hdr->getFileClass() == T::ELFClass && "invalid ELF file class"); - // From the header, grab informations about the section header table. - auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff; - auto SectionHdrNumEntries = Hdr->e_shnum; - auto SectionEntrySize = Hdr->e_shentsize; + // From the header, grab information about the section header table. + uint64_t SectionHdrAddress = Hdr->e_shoff; + uint16_t SectionHdrNumEntries = Hdr->e_shnum; + uint16_t SectionEntrySize = Hdr->e_shentsize; + + if (sizeof(typename T::Section) > SectionEntrySize) + return false; + if (SectionHdrNumEntries == 0) + return false; // Collect all the section headers, we need them to look up the // reflection sections (by name) and the string table. + // We read the section headers from the FileBuffer, since they are + // not mapped in the child process. std::vector SecHdrVec; for (unsigned I = 0; I < SectionHdrNumEntries; ++I) { - auto SecBuf = this->getReader().readBytes( - RemoteAddress(SectionHdrAddress + (I * SectionEntrySize)), - SectionEntrySize); + uint64_t Offset = SectionHdrAddress + (I * SectionEntrySize); + auto SecBuf = readData(Offset, sizeof(typename T::Section)); if (!SecBuf) return false; - auto SecHdr = - reinterpret_cast(SecBuf.get()); + const typename T::Section *SecHdr = + reinterpret_cast(SecBuf); + SecHdrVec.push_back(SecHdr); } @@ -434,30 +466,54 @@ class ReflectionContext typename T::Offset StrTabOffset = SecHdrStrTab->sh_offset; typename T::Size StrTabSize = SecHdrStrTab->sh_size; - auto StrTabStart = - RemoteAddress(ImageStart.getAddressData() + StrTabOffset); - auto StrTabBuf = this->getReader().readBytes(StrTabStart, StrTabSize); - auto StrTab = reinterpret_cast(StrTabBuf.get()); - - auto findELFSectionByName = [&](llvm::StringRef Name) - -> std::pair, uint64_t> { - // Now for all the sections, find their name. - for (const typename T::Section *Hdr : SecHdrVec) { - uint32_t Offset = Hdr->sh_name; - auto SecName = std::string(StrTab + Offset); - if (SecName != Name) - continue; - auto SecStart = - RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); - auto SecSize = Hdr->sh_size; - auto SecBuf = this->getReader().readBytes(SecStart, SecSize); - auto SecContents = RemoteRef(SecStart.getAddressData(), - SecBuf.get()); - savedBuffers.push_back(std::move(SecBuf)); - return {SecContents, SecSize}; - } - return {nullptr, 0}; - }; + auto StrTabBuf = readData(StrTabOffset, StrTabSize); + if (!StrTabBuf) + return false; + auto StrTab = reinterpret_cast(StrTabBuf); + bool Error = false; + auto findELFSectionByName = + [&](llvm::StringRef Name) -> std::pair, uint64_t> { + if (Error) + return {nullptr, 0}; + // Now for all the sections, find their name. + for (const typename T::Section *Hdr : SecHdrVec) { + uint32_t Offset = Hdr->sh_name; + const char *Start = (const char *)StrTab + Offset; + uint64_t Size = strnlen(Start, StrTabSize - Offset); + if (Size > StrTabSize - Offset) { + Error = true; + break; + } + std::string SecName(Start, Size); + if (SecName != Name) + continue; + RemoteAddress SecStart = + RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); + auto SecSize = Hdr->sh_size; + MemoryReader::ReadBytesResult SecBuf; + if (FileBuffer.hasValue()) { + // sh_offset gives us the offset to the section in the file, + // while sh_addr gives us the offset in the process. + auto Offset = Hdr->sh_offset; + if (FileBuffer->allocatedSize() > Offset + Size) { + Error = true; + break; + } + auto *Buf = malloc(SecSize); + SecBuf = MemoryReader::ReadBytesResult( + Buf, [](const void *ptr) { free(const_cast(ptr)); }); + memcpy((void *)Buf, + (const void *)((uint64_t)FileBuffer->base() + Offset), Size); + } else { + SecBuf = this->getReader().readBytes(SecStart, SecSize); + } + auto SecContents = + RemoteRef(SecStart.getAddressData(), SecBuf.get()); + savedBuffers.push_back(std::move(SecBuf)); + return {SecContents, SecSize}; + } + return {nullptr, 0}; + }; SwiftObjectFileFormatELF ObjectFileFormat; auto FieldMdSec = findELFSectionByName( @@ -473,6 +529,9 @@ class ReflectionContext auto ReflStrMdSec = findELFSectionByName( ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); + if (Error) + return false; + // We succeed if at least one of the sections is present in the // ELF executable. if (FieldMdSec.first == nullptr && @@ -492,12 +551,28 @@ class ReflectionContext {ReflStrMdSec.first, ReflStrMdSec.second}}; this->addReflectionInfo(info); - - savedBuffers.push_back(std::move(Buf)); return true; } - - bool readELF(RemoteAddress ImageStart) { + + /// Parses metadata information from an ELF image. Because the Section + /// Header Table maybe be missing (for example, when reading from a + /// process) this method optionally receives a buffer with the contents + /// of the image's file, from where it will the necessary information. + /// + /// + /// \param[in] ImageStart + /// A remote address pointing to the start of the image in the running + /// process. + /// + /// \param[in] FileBuffer + /// A buffer which contains the contents of the image's file + /// in disk. If missing, all the information will be read using the + /// instance's memory reader. + /// + /// \return + /// /b True if the metadata information was parsed successfully, + /// /b false otherwise. + bool readELF(RemoteAddress ImageStart, llvm::Optional FileBuffer) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr)); @@ -510,9 +585,11 @@ class ReflectionContext // Check if we have a ELFCLASS32 or ELFCLASS64 unsigned char FileClass = Hdr->getFileClass(); if (FileClass == llvm::ELF::ELFCLASS64) { - return readELFSections>(ImageStart); + return readELFSections>( + ImageStart, FileBuffer); } else if (FileClass == llvm::ELF::ELFCLASS32) { - return readELFSections>(ImageStart); + return readELFSections>( + ImageStart, FileBuffer); } else { return false; } @@ -542,15 +619,16 @@ class ReflectionContext if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') { return readPECOFF(ImageStart); } - + + // ELF. if (MagicBytes[0] == llvm::ELF::ElfMagic[0] && MagicBytes[1] == llvm::ELF::ElfMagic[1] && MagicBytes[2] == llvm::ELF::ElfMagic[2] && MagicBytes[3] == llvm::ELF::ElfMagic[3]) { - return readELF(ImageStart); + return readELF(ImageStart, llvm::Optional()); } - + // We don't recognize the format. return false; } From ee6c6f4bf2145af89c6e6f3695973a55aa613aff Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 12 Aug 2020 09:52:14 -0700 Subject: [PATCH 095/663] [CodeCompletion] Stop marking non-target function bodies 'Skipped' --- include/swift/AST/Decl.h | 3 +-- lib/AST/Decl.cpp | 3 +-- lib/Parse/ParseDecl.cpp | 15 ++++++--------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 67e39b9800ef4..0d690d1db3f92 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5935,8 +5935,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// Note that parsing for the body was delayed. void setBodyDelayed(SourceRange bodyRange) { - assert(getBodyKind() == BodyKind::None || - getBodyKind() == BodyKind::Skipped); + assert(getBodyKind() == BodyKind::None); assert(bodyRange.isValid()); BodyRange = bodyRange; setBodyKind(BodyKind::Unparsed); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 1e34a4af48150..4081ce38025e9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6728,8 +6728,7 @@ void AbstractFunctionDecl::setBody(BraceStmt *S, BodyKind NewBodyKind) { void AbstractFunctionDecl::setBodyToBeReparsed(SourceRange bodyRange) { assert(bodyRange.isValid()); - assert(getBodyKind() == BodyKind::None || - getBodyKind() == BodyKind::Skipped || + assert(getBodyKind() == BodyKind::Unparsed || getBodyKind() == BodyKind::Parsed || getBodyKind() == BodyKind::TypeChecked); assert(getASTContext().SourceMgr.rangeContainsTokenLoc( diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 28f5e4c2989a9..bebab2b33438f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -6248,15 +6248,12 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD, AFD->setBodyDelayed(BodyRange); - if (isCodeCompletionFirstPass()) { - if (SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) { - State->setCodeCompletionDelayedDeclState( - SourceMgr, L->getBufferID(), - CodeCompletionDelayedDeclKind::FunctionBody, - PD_Default, AFD, BodyRange, BeginParserPosition.PreviousLoc); - } else { - AFD->setBodySkipped(BodyRange); - } + if (isCodeCompletionFirstPass() && + SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) { + State->setCodeCompletionDelayedDeclState( + SourceMgr, L->getBufferID(), + CodeCompletionDelayedDeclKind::FunctionBody, + PD_Default, AFD, BodyRange, BeginParserPosition.PreviousLoc); } } From cf773c3d0e9f647328846810907b79551b45a922 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 12 Aug 2020 12:06:46 -0700 Subject: [PATCH 096/663] [Explicit Module Loader] Refactor ESWL to use findModule instead of findModuleFilesInDirectory And add isFramework to the Explicit Module Map and its parser. --- .../swift/Frontend/ModuleInterfaceLoader.h | 30 ++++++++++---- .../Serialization/SerializedModuleLoader.h | 12 +++--- lib/Frontend/ModuleInterfaceLoader.cpp | 41 ++++++++++++------- lib/Serialization/SerializedModuleLoader.cpp | 2 - 4 files changed, 56 insertions(+), 29 deletions(-) diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 3eac993f14f61..84a23442e0ff2 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -112,6 +112,7 @@ #include "swift/Frontend/ModuleInterfaceSupport.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "llvm/Support/StringSaver.h" +#include namespace clang { class CompilerInstance; @@ -133,14 +134,22 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { explicit ExplicitSwiftModuleLoader(ASTContext &ctx, DependencyTracker *tracker, ModuleLoadingMode loadMode, bool IgnoreSwiftSourceInfoFile); + + bool findModule(AccessPathElem moduleID, + SmallVectorImpl *moduleInterfacePath, + std::unique_ptr *moduleBuffer, + std::unique_ptr *moduleDocBuffer, + std::unique_ptr *moduleSourceInfoBuffer, + bool &isFramework, bool &isSystemModule) override; + std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer, - bool IsFramework) override; + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; bool canImportModule(Located mID) override; @@ -173,6 +182,8 @@ struct ExplicitModuleInfo { std::string moduleSourceInfoPath; // Opened buffer for the .swiftmodule file. std::unique_ptr moduleBuffer; + // A flag that indicates whether this module is a framework + bool isFramework; }; /// Parser of explicit module maps passed into the compiler. @@ -182,12 +193,14 @@ struct ExplicitModuleInfo { // "modulePath": "A.swiftmodule", // "docPath": "A.swiftdoc", // "sourceInfoPath": "A.swiftsourceinfo" +// "isFramework": false // }, // { // "moduleName": "B", // "modulePath": "B.swiftmodule", // "docPath": "B.swiftdoc", // "sourceInfoPath": "B.swiftsourceinfo" +// "isFramework": false // } // ] class ExplicitModuleMapParser { @@ -249,6 +262,9 @@ class ExplicitModuleMapParser { result.moduleDocPath = val.str(); } else if (key == "sourceInfoPath") { result.moduleSourceInfoPath = val.str(); + } else if (key == "isFramework") { + std::istringstream is(val.str()); + is >> std::boolalpha >> result.isFramework; } else { // Being forgiving for future fields. continue; diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index ab6c5cbb96ab1..1cda5272cbb7a 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -73,12 +73,12 @@ class SerializedModuleLoaderBase : public ModuleLoader { StringRef extension) const; using AccessPathElem = Located; - bool findModule(AccessPathElem moduleID, - SmallVectorImpl *moduleInterfacePath, - std::unique_ptr *moduleBuffer, - std::unique_ptr *moduleDocBuffer, - std::unique_ptr *moduleSourceInfoBuffer, - bool &isFramework, bool &isSystemModule); + virtual bool findModule(AccessPathElem moduleID, + SmallVectorImpl *moduleInterfacePath, + std::unique_ptr *moduleBuffer, + std::unique_ptr *moduleDocBuffer, + std::unique_ptr *moduleSourceInfoBuffer, + bool &isFramework, bool &isSystemModule); /// Attempts to search the provided directory for a loadable serialized /// .swiftmodule with the provided `ModuleFilename`. Subclasses must diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 27cbdd7ee8b22..7cb56c08e5301 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1522,29 +1522,30 @@ ExplicitSwiftModuleLoader::ExplicitSwiftModuleLoader( ExplicitSwiftModuleLoader::~ExplicitSwiftModuleLoader() { delete &Impl; } -std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer, - bool IsFramework) { +bool ExplicitSwiftModuleLoader::findModule(AccessPathElem ModuleID, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool &IsFramework, bool &IsSystemModule) { StringRef moduleName = ModuleID.Item.str(); auto it = Impl.ExplicitModuleMap.find(moduleName); // If no explicit module path is given matches the name, return with an // error code. if (it == Impl.ExplicitModuleMap.end()) { - return std::make_error_code(std::errc::not_supported); + return false; } auto &moduleInfo = it->getValue(); if (moduleInfo.moduleBuffer) { // We found an explicit module matches the given name, give the buffer // back to the caller side. *ModuleBuffer = std::move(moduleInfo.moduleBuffer); - return std::error_code(); + return true; } + // Set IsFramework bit according to the moduleInfo + IsFramework = moduleInfo.isFramework; + auto &fs = *Ctx.SourceMgr.getFileSystem(); // Open .swiftmodule file auto moduleBuf = fs.getBufferForFile(moduleInfo.modulePath); @@ -1552,7 +1553,7 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( // We cannot read the module content, diagnose. Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, moduleInfo.modulePath); - return moduleBuf.getError(); + return false; } assert(moduleBuf); @@ -1568,13 +1569,13 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( // We cannot read the module content, diagnose. Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, moduleInfo.modulePath); - return moduleBuf.getError(); + return false; } } else { // We cannot read the module content, diagnose. Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, moduleInfo.modulePath); - return forwardingModule.getError(); + return false; } } assert(moduleBuf); @@ -1593,7 +1594,19 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( if (moduleSourceInfoBuf) *ModuleSourceInfoBuffer = std::move(moduleSourceInfoBuf.get()); } - return std::error_code(); + return true; +} + +std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + llvm_unreachable("Not supported in the Explicit Swift Module Loader."); + return std::make_error_code(std::errc::not_supported); } bool ExplicitSwiftModuleLoader::canImportModule( diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 57cad1cdc009c..a82ee47568e5a 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -682,7 +682,6 @@ FileUnit *SerializedModuleLoaderBase::loadAST( std::unique_ptr moduleSourceInfoInputBuffer, bool isFramework) { assert(moduleInputBuffer); - StringRef moduleBufferID = moduleInputBuffer->getBufferIdentifier(); StringRef moduleDocBufferID; if (moduleDocInputBuffer) @@ -993,7 +992,6 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, StringRef moduleInterfacePathStr = Ctx.AllocateCopy(moduleInterfacePath.str()); - auto *file = loadAST(*M, moduleID.Loc, moduleInterfacePathStr, std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), From 198519c75ff0f0d618ce65a403e1a81e0f05d7bd Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 12 Aug 2020 15:22:09 -0400 Subject: [PATCH 097/663] SIL: Fix TypeExpansionContext() constructor to get the right DeclContext from a SILFunction Using the SILFunction's DeclContext produces the wrong result for the @main function, because it returns the ModuleDecl even in a non-WMO build. Instead, let's always just use SILModule::getAssociatedContext(), which also simplifies the code here. Fixes . --- lib/SIL/IR/SILFunctionType.cpp | 12 +------ test/SILGen/opaque_result_type_private.swift | 34 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 test/SILGen/opaque_result_type_private.swift diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 3838b09d1aef3..5fe7a5d592ae3 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -4477,19 +4477,9 @@ StringRef SILFunctionType::ABICompatibilityCheckResult::getMessage() const { llvm_unreachable("Covered switch isn't completely covered?!"); } -static DeclContext *getDeclContextForExpansion(const SILFunction &f) { - auto *dc = f.getDeclContext(); - if (!dc) - dc = f.getModule().getSwiftModule(); - auto *currentModule = f.getModule().getSwiftModule(); - if (!dc || !dc->isChildContextOf(currentModule)) - dc = currentModule; - return dc; -} - TypeExpansionContext::TypeExpansionContext(const SILFunction &f) : expansion(f.getResilienceExpansion()), - inContext(getDeclContextForExpansion(f)), + inContext(f.getModule().getAssociatedContext()), isContextWholeModule(f.getModule().isWholeModule()) {} CanSILFunctionType SILFunction::getLoweredFunctionTypeInContext( diff --git a/test/SILGen/opaque_result_type_private.swift b/test/SILGen/opaque_result_type_private.swift new file mode 100644 index 0000000000000..25cff253f4d59 --- /dev/null +++ b/test/SILGen/opaque_result_type_private.swift @@ -0,0 +1,34 @@ +// RUN: %target-swift-emit-silgen -primary-file %s -disable-availability-checking | %FileCheck %s +// RUN: %target-swift-emit-sil -primary-file %s -O -disable-availability-checking + +// CHECK-LABEL: sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { + +// CHECK: [[BOX:%.*]] = alloc_stack $PrivateClass +// CHECK: [[FN:%.*]] = function_ref @$s26opaque_result_type_private19returnPrivateOpaqueQryF : $@convention(thin) () -> @out PrivateClass +// CHECK: apply [[FN]]([[BOX]]) : $@convention(thin) () -> @out PrivateClass +// CHECK: [[RESULT:%.*]] = load [take] [[BOX]] : $*PrivateClass +// CHECK: destroy_value [[RESULT]] : $PrivateClass +// CHECK: dealloc_stack [[BOX]] : $*PrivateClass +_ = returnPrivateOpaque() + +// CHECK: [[BOX:%.*]] = alloc_stack $LocalClass +// CHECK: [[FN:%.*]] = function_ref @$s26opaque_result_type_private17returnLocalOpaqueQryF : $@convention(thin) () -> @out LocalClass +// CHECK: apply [[FN]]([[BOX]]) : $@convention(thin) () -> @out LocalClass +// CHECK: [[RESULT:%.*]] = load [take] [[BOX]] : $*LocalClass +// CHECK: destroy_value [[RESULT]] : $LocalClass +// CHECK: dealloc_stack [[BOX]] : $*LocalClass +_ = returnLocalOpaque() + +fileprivate class PrivateClass {} + +// CHECK-LABEL: sil hidden [ossa] @$s26opaque_result_type_private19returnPrivateOpaqueQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s26opaque_result_type_private19returnPrivateOpaqueQryF", 0) 🦸 +func returnPrivateOpaque() -> some Any { + return PrivateClass() +} + +// CHECK-LABEL: sil hidden [ossa] @$s26opaque_result_type_private17returnLocalOpaqueQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s26opaque_result_type_private17returnLocalOpaqueQryF", 0) 🦸 +func returnLocalOpaque() -> some Any { + class LocalClass {} + + return LocalClass() +} From 6b61818fffe82ad41859327803084103e5eb1d8f Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Wed, 12 Aug 2020 12:37:13 -0700 Subject: [PATCH 098/663] Revert "[cxx-interop] Import `typedef`-ed template instantiations (#32950)" This reverts commit 643aa2d8961c2f86b931658d026329adf00a35a9. --- docs/ABI/Mangling.rst | 37 ---------------- docs/CppInteroperabilityManifesto.md | 42 +------------------ include/swift/Strings.h | 4 -- lib/AST/ASTMangler.cpp | 9 ---- lib/ClangImporter/ImportDecl.cpp | 29 +++---------- lib/ClangImporter/ImportName.cpp | 30 ------------- lib/ClangImporter/SwiftLookupTable.cpp | 23 +--------- .../Cxx/templates/Inputs/canonical-types.h | 18 -------- .../decl-with-definition-including-members.h | 26 ------------ .../templates/Inputs/decl-with-definition.h | 24 ----------- .../Inputs/decl-with-primitive-argument.h | 12 ------ .../Inputs/decl-without-definition.h | 20 --------- .../Inputs/eager-instantiation-problems.h | 24 ----------- .../Inputs/explicit-specialization.h | 29 ------------- ...kage-of-swift-symbols-for-imported-types.h | 21 ---------- test/Interop/Cxx/templates/Inputs/mangling.h | 11 ----- .../Cxx/templates/Inputs/module.modulemap | 39 ----------------- .../Cxx/templates/Inputs/using-directive.h | 17 -------- .../canonical-types-module-interface.swift | 15 ------- .../Cxx/templates/canonical-types.swift | 15 ------- ...cl-with-definition-including-members.swift | 16 ------- .../decl-with-definition-irgen.swift | 33 --------------- .../decl-with-definition-silgen.swift | 21 ---------- .../Cxx/templates/decl-with-definition.swift | 16 ------- .../decl-with-primitive-argument.swift | 15 ------- ...-without-definition-module-interface.swift | 15 ------- .../templates/decl-without-definition.swift | 16 ------- test/Interop/Cxx/templates/demangling.swift | 12 ------ .../eager-instatiation-problems.swift | 32 -------------- .../templates/explicit-specialization.swift | 20 --------- ...ift-symbols-for-imported-types-irgen.swift | 28 ------------- .../Cxx/templates/mangling-irgen.swift | 18 -------- .../Cxx/templates/mangling-silgen.swift | 20 --------- .../using-directive-module-interface.swift | 15 ------- .../Cxx/templates/using-directive.swift | 16 ------- test/lit.cfg | 2 - 36 files changed, 8 insertions(+), 732 deletions(-) delete mode 100644 test/Interop/Cxx/templates/Inputs/canonical-types.h delete mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h delete mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-definition.h delete mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h delete mode 100644 test/Interop/Cxx/templates/Inputs/decl-without-definition.h delete mode 100644 test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h delete mode 100644 test/Interop/Cxx/templates/Inputs/explicit-specialization.h delete mode 100644 test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h delete mode 100644 test/Interop/Cxx/templates/Inputs/mangling.h delete mode 100644 test/Interop/Cxx/templates/Inputs/module.modulemap delete mode 100644 test/Interop/Cxx/templates/Inputs/using-directive.h delete mode 100644 test/Interop/Cxx/templates/canonical-types-module-interface.swift delete mode 100644 test/Interop/Cxx/templates/canonical-types.swift delete mode 100644 test/Interop/Cxx/templates/decl-with-definition-including-members.swift delete mode 100644 test/Interop/Cxx/templates/decl-with-definition-irgen.swift delete mode 100644 test/Interop/Cxx/templates/decl-with-definition-silgen.swift delete mode 100644 test/Interop/Cxx/templates/decl-with-definition.swift delete mode 100644 test/Interop/Cxx/templates/decl-with-primitive-argument.swift delete mode 100644 test/Interop/Cxx/templates/decl-without-definition-module-interface.swift delete mode 100644 test/Interop/Cxx/templates/decl-without-definition.swift delete mode 100644 test/Interop/Cxx/templates/demangling.swift delete mode 100644 test/Interop/Cxx/templates/eager-instatiation-problems.swift delete mode 100644 test/Interop/Cxx/templates/explicit-specialization.swift delete mode 100644 test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift delete mode 100644 test/Interop/Cxx/templates/mangling-irgen.swift delete mode 100644 test/Interop/Cxx/templates/mangling-silgen.swift delete mode 100644 test/Interop/Cxx/templates/using-directive-module-interface.swift delete mode 100644 test/Interop/Cxx/templates/using-directive.swift diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index f35339c9ebb70..a65799b8c53cd 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -1107,40 +1107,3 @@ nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` mo .. code:: sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct - -Importing C++ class template instantiations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A class template instantiation is imported as a struct named -``__CxxTemplateInst`` plus Itanium mangled type of the instantiation (see the -``type`` production in the Itanium specification). Note that Itanium mangling is -used on all platforms, regardless of the ABI of the C++ toolchain, to ensure -that the mangled name is a valid Swift type name (this is not the case for MSVC -mangled names). A prefix with a double underscore (to ensure we have a reserved -C++ identifier) is added to limit the possibility for conflicts with names of -user-defined structs. The struct is notionally defined in the ``__C`` module, -similarly to regular C and C++ structs and classes. Consider the following C++ -module: - -.. code-block:: c++ - - template - struct MagicWrapper { - T t; - }; - - struct MagicNumber {}; - - typedef MagicWrapper WrappedMagicNumber; - -``WrappedMagicNumber`` is imported as a typealias for struct -``__CxxTemplateInst12MagicWrapperI11MagicNumberE``. Interface of the imported -module looks as follows: - -.. code-block:: swift - - struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { - var t: MagicNumber - } - struct MagicNumber {} - typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE diff --git a/docs/CppInteroperabilityManifesto.md b/docs/CppInteroperabilityManifesto.md index b23c914268c1b..f3a8df51820d2 100644 --- a/docs/CppInteroperabilityManifesto.md +++ b/docs/CppInteroperabilityManifesto.md @@ -67,7 +67,6 @@ Assumptions: + [Function templates: calls with generic type parameters](#function-templates-calls-with-generic-type-parameters) + [Function templates: importing as real generic functions](#function-templates-importing-as-real-generic-functions) + [Class templates](#class-templates) - + [Class templates: importing instantiation behind typedef](#class-templates-importing-instantiation-behind-typedef) + [Class templates: importing specific specilalizations](#class-templates-importing-specific-specilalizations) + [Class templates: using with generic type parameters](#class-templates-using-with-generic-type-parameters) + [Class templates: using in generic code through a synthesized protocol](#class-templates-using-in-generic-code-through-a-synthesized-protocol) @@ -2576,45 +2575,6 @@ We could ignore explicit specializations of function templates, because they don't affect the API. Explicit specializations of class templates can dramatically change the API of the type. -### Class templates: Importing full class template instantiations - -A class template instantiation could be imported as a struct named -`__CxxTemplateInst` plus Itanium mangled type of the instantiation (see the -`type` production in the Itanium specification). Note that Itanium mangling is -used on all platforms, regardless of the ABI of the C++ toolchain, to ensure -that the mangled name is a valid Swift type name (this is not the case for MSVC -mangled names). A prefix with a double underscore (to ensure we have a reserved -C++ identifier) is added to limit the possibility for conflicts with names of -user-defined structs. The struct is notionally defined in the `__C` module, -similarly to regular C and C++ structs and classes. Consider the following C++ -module: - -```c++ -// C++ header. - -template -struct MagicWrapper { - T t; -}; -struct MagicNumber {}; - -typedef MagicWrapper WrappedMagicNumber; -``` - -`WrappedMagicNumber` will be imported as a typealias for a struct -`__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Interface of the imported -module will look as follows: - -```swift -// C++ header imported to Swift. - -struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { - var t: MagicNumber -} -struct MagicNumber {} -typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE -``` - ### Class templates: importing specific specilalizations Just like with calls to C++ function templates, it is easy to compile a use of a @@ -2792,7 +2752,7 @@ func useConcrete() { ### Class templates: importing as real generic structs -If we know the complete set of allowed type arguments to a C++ struct +If we know the complete set of allowed type arguments to a C++ function template, we could import it as an actual Swift generic struct. Every method of that struct will perform dynamic dispatch based on type parameters. See the section about function templates for more details. diff --git a/include/swift/Strings.h b/include/swift/Strings.h index 69b29ff4a52b9..32a7bb2d0072c 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -38,10 +38,6 @@ constexpr static const StringLiteral MANGLING_MODULE_OBJC = "__C"; constexpr static const StringLiteral MANGLING_MODULE_CLANG_IMPORTER = "__C_Synthesized"; -/// The name prefix for C++ template instantiation imported as a Swift struct. -constexpr static const StringLiteral CXX_TEMPLATE_INST_PREFIX = - "__CxxTemplateInst"; - constexpr static const StringLiteral SEMANTICS_PROGRAMTERMINATION_POINT = "programtermination_point"; diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index be1c4af4e0ea1..e013ad5db8b3c 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -39,7 +39,6 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" @@ -2115,7 +2114,6 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { // Always use Clang names for imported Clang declarations, unless they don't // have one. auto tryAppendClangName = [this, decl]() -> bool { - auto *nominal = dyn_cast(decl); auto namedDecl = getClangDeclForMangling(decl); if (!namedDecl) return false; @@ -2128,13 +2126,6 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { appendIdentifier(interface->getObjCRuntimeNameAsString()); } else if (UseObjCRuntimeNames && protocol) { appendIdentifier(protocol->getObjCRuntimeNameAsString()); - } else if (auto ctsd = dyn_cast(namedDecl)) { - // If this is a `ClassTemplateSpecializationDecl`, it was - // imported as a Swift decl with `__CxxTemplateInst...` name. - // `ClassTemplateSpecializationDecl`'s name does not include information about - // template arguments, and in order to prevent name clashes we use the - // name of the Swift decl which does include template arguments. - appendIdentifier(nominal->getName().str()); } else { appendIdentifier(namedDecl->getName()); } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index b0ca58c4c4047..e35b0aed470b7 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3477,33 +3477,14 @@ namespace { Decl *VisitClassTemplateSpecializationDecl( const clang::ClassTemplateSpecializationDecl *decl) { - // `Sema::isCompleteType` will try to instantiate the class template as a - // side-effect and we rely on this here. `decl->getDefinition()` can - // return nullptr before the call to sema and return its definition - // afterwards. - if (!Impl.getClangSema().isCompleteType( - decl->getLocation(), - Impl.getClangASTContext().getRecordType(decl))) { - // If we got nullptr definition now it means the type is not complete. - // We don't import incomplete types. - return nullptr; - } - auto def = dyn_cast( - decl->getDefinition()); - assert(def && "Class template instantiation didn't have definition"); - // FIXME: This will instantiate all members of the specialization (and detect - // instantiation failures in them), which can be more than is necessary - // and is more than what Clang does. As a result we reject some C++ - // programs that Clang accepts. - Impl.getClangSema().InstantiateClassTemplateSpecializationMembers( - def->getLocation(), def, clang::TSK_ExplicitInstantiationDefinition); - - return VisitRecordDecl(def); + // FIXME: We could import specializations, but perhaps only as unnamed + // structural types. + return nullptr; } Decl *VisitClassTemplatePartialSpecializationDecl( - const clang::ClassTemplatePartialSpecializationDecl *decl) { - // Note: partial template specializations are not imported. + const clang::ClassTemplatePartialSpecializationDecl *decl) { + // Note: templates are not imported. return nullptr; } diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 46817ce93de2a..1611d20507369 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -31,10 +31,8 @@ #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Parser.h" -#include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/Mangle.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" @@ -1700,34 +1698,6 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, } } - if (auto classTemplateSpecDecl = - dyn_cast(D)) { - if (!isa(D)) { - - auto &astContext = classTemplateSpecDecl->getASTContext(); - // Itanium mangler produces valid Swift identifiers, use it to generate a name for - // this instantiation. - clang::MangleContext *mangler = clang::ItaniumMangleContext::create( - astContext, astContext.getDiagnostics()); - llvm::SmallString<128> storage; - llvm::raw_svector_ostream buffer(storage); - mangler->mangleTypeName(astContext.getRecordType(classTemplateSpecDecl), - buffer); - - // The Itanium mangler does not provide a way to get the mangled - // representation of a type. Instead, we call mangleTypeName() that - // returns the name of the RTTI typeinfo symbol, and remove the _ZTS - // prefix. Then we prepend __CxxTemplateInst to reduce chances of conflict - // with regular C and C++ structs. - llvm::SmallString<128> mangledNameStorage; - llvm::raw_svector_ostream mangledName(mangledNameStorage); - assert(buffer.str().take_front(4) == "_ZTS"); - mangledName << CXX_TEMPLATE_INST_PREFIX << buffer.str().drop_front(4); - - baseName = swiftCtx.getIdentifier(mangledName.str()).get(); - } - } - // swift_newtype-ed declarations may have common words with the type name // stripped. if (auto newtypeDecl = findSwiftNewtype(D, clangSema, version)) { diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 3ac0d0fe45d0c..74a64dcb025d5 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1881,16 +1881,10 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table, // struct names when relevant, not just pointer names. That way we can check // both CFDatabase.def and the objc_bridge attribute and cover all our bases. if (auto *tagDecl = dyn_cast(named)) { - // We add entries for ClassTemplateSpecializations that don't have - // definition. It's possible that the decl will be instantiated by - // SwiftDeclConverter later on. We cannot force instantiating - // ClassTemplateSPecializations here because we're currently writing the - // AST, so we cannot modify it. - if (!isa(named) && - !tagDecl->getDefinition()) { + if (!tagDecl->getDefinition()) return; - } } + // If we have a name to import as, add this entry to the table. auto currentVersion = ImportNameVersion::fromOptions(nameImporter.getLangOpts()); @@ -2083,19 +2077,6 @@ void SwiftLookupTableWriter::populateTableWithDecl(SwiftLookupTable &table, // Add this entry to the lookup table. addEntryToLookupTable(table, named, nameImporter); - if (auto typedefDecl = dyn_cast(named)) { - if (auto typedefType = dyn_cast( - typedefDecl->getUnderlyingType())) { - if (auto CTSD = dyn_cast( - typedefType->getAsTagDecl())) { - // Adding template instantiation behind typedef as a top-level entry - // so the instantiation appears in the API. - assert(!isa(CTSD) && - "Class template partial specialization cannot appear behind typedef"); - addEntryToLookupTable(table, CTSD, nameImporter); - } - } - } } void SwiftLookupTableWriter::populateTable(SwiftLookupTable &table, diff --git a/test/Interop/Cxx/templates/Inputs/canonical-types.h b/test/Interop/Cxx/templates/Inputs/canonical-types.h deleted file mode 100644 index 865c85a882cf9..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/canonical-types.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H - -template -struct MagicWrapper { - T t; - int getValuePlusArg(int arg) const { return t.getValue() + arg; } -}; - -struct IntWrapper { - int value; - int getValue() const { return value; } -}; - -typedef MagicWrapper WrappedMagicNumberA; -typedef MagicWrapper WrappedMagicNumberB; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h deleted file mode 100644 index 4c772c9dfaca0..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H - -template -struct MagicWrapper { - T t; - int getValuePlusArg(int arg) const { return t.getValue() + arg; } -}; - -struct IntWrapper { - int value; - int getValue() const { return value; } -}; - -inline int forceInstantiation() { - auto t = MagicWrapper(); - return t.getValuePlusArg(14); -} - -// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition -// because function above forced the instantiation. Its members are fully -// instantiated, so nothing needs to be explicitly instantiated by the Swift -// compiler. -typedef MagicWrapper FullyDefinedMagicallyWrappedInt; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h deleted file mode 100644 index d8fb7b56f676b..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/decl-with-definition.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H - -template -struct MagicWrapper { - T t; - int getValuePlusArg(int arg) const { return t.getValue() + arg; } -}; - -struct IntWrapper { - int value; - int getValue() const { return value; } -}; - -inline MagicWrapper forceInstantiation() { - return MagicWrapper(); -} - -// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition -// because function above forced the instantiation. Its members are not -// instantiated though, the Swift compiler needs to instantiate them. -typedef MagicWrapper PartiallyDefinedMagicallyWrappedInt; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h deleted file mode 100644 index 2bba7d493e342..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H - -template -struct MagicWrapper { - T t; - int getValuePlusArg(int arg) const { return t + arg; } -}; - -typedef MagicWrapper WrappedMagicInt; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-without-definition.h b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h deleted file mode 100644 index a4eb3506672b2..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/decl-without-definition.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H - -template -struct MagicWrapper { - T t; - int getValuePlusArg(int arg) const { return t.getValue() + arg; } -}; - -struct IntWrapper { - int value; - int getValue() const { return value; } -}; - -// The ClassTemplateSpecializationDecl node for MagicWrapper doesn't have a -// definition in Clang because nothing in this header required the -// instantiation. Therefore, the Swift compiler must trigger instantiation. -typedef MagicWrapper MagicallyWrappedIntWithoutDefinition; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h deleted file mode 100644 index 5992054ae9d3d..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H - -struct MagicNumber { - int getInt() const { return 42; } -}; - -template -struct MagicWrapper { - void callGetInt() const { - T::getIntDoesNotExist(); - } - - template int sfinaeGetInt(A a, decltype(&A::getInt)) { - return a.getInt(); - } - template int sfinaeGetInt(A a, ...) { - return -42; - } -}; - -typedef MagicWrapper BrokenMagicWrapper; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H diff --git a/test/Interop/Cxx/templates/Inputs/explicit-specialization.h b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h deleted file mode 100644 index 62b9f7aa030af..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/explicit-specialization.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H - -struct SpecializedIntWrapper { - int value; - int getValue() const { return value; } -}; - -struct NonSpecializedIntWrapper { - int value; - int getValue() const { return value; } -}; - -template -struct MagicWrapper { - T t; - int doubleIfSpecializedElseTriple() const { return 3 * t.getValue(); } -}; - -template <> -struct MagicWrapper { - SpecializedIntWrapper t; - int doubleIfSpecializedElseTriple() const { return 2 * t.getValue(); } -}; - -typedef MagicWrapper WrapperWithSpecialization; -typedef MagicWrapper WrapperWithoutSpecialization; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H diff --git a/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h deleted file mode 100644 index d700209d93873..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H - -template -struct MagicWrapper { - T t; - int callGetInt() const { - return t.getInt() + 5; - } -}; - -struct MagicNumber { - // Swift runtime defines many value witness tables for types with some common layouts. - // This struct's uncommon size forces the compiler to define a new value witness table instead of reusing one from the runtime. - char forceVWTableCreation[57]; - int getInt() const { return 12; } -}; - -typedef MagicWrapper WrappedMagicNumber; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/mangling.h b/test/Interop/Cxx/templates/Inputs/mangling.h deleted file mode 100644 index f135b52747600..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/mangling.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H - -template -struct MagicWrapper {}; - -typedef MagicWrapper WrappedMagicInt; -typedef MagicWrapper WrappedMagicBool; - - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H diff --git a/test/Interop/Cxx/templates/Inputs/module.modulemap b/test/Interop/Cxx/templates/Inputs/module.modulemap deleted file mode 100644 index af6d28e675a40..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/module.modulemap +++ /dev/null @@ -1,39 +0,0 @@ -module DeclWithPrimitiveArgument { - header "decl-with-primitive-argument.h" -} - -module DeclWithoutDefinition { - header "decl-without-definition.h" -} - -module DeclWithDefinition { - header "decl-with-definition.h" -} - -module DeclWithDefinitionIncludingMembers { - header "decl-with-definition-including-members.h" -} - -module CanonicalTypes { - header "canonical-types.h" -} - -module ExplicitSpecialization { - header "explicit-specialization.h" -} - -module UsingDirective { - header "using-directive.h" -} - -module EagerInstantiationProblems { - header "eager-instantiation-problems.h" -} - -module Mangling { - header "mangling.h" -} - -module LinkageOfSwiftSymbolsForImportedTypes { - header "linkage-of-swift-symbols-for-imported-types.h" -} diff --git a/test/Interop/Cxx/templates/Inputs/using-directive.h b/test/Interop/Cxx/templates/Inputs/using-directive.h deleted file mode 100644 index 076660e8a19e4..0000000000000 --- a/test/Interop/Cxx/templates/Inputs/using-directive.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H -#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H - -template -struct MagicWrapper { - T t; - int getValuePlusArg(int arg) const { return t.getValue() + arg; } -}; - -struct IntWrapper { - int value; - int getValue() const { return value; } -}; - -using UsingWrappedMagicNumber = MagicWrapper; - -#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H diff --git a/test/Interop/Cxx/templates/canonical-types-module-interface.swift b/test/Interop/Cxx/templates/canonical-types-module-interface.swift deleted file mode 100644 index 3a90d1d44311a..0000000000000 --- a/test/Interop/Cxx/templates/canonical-types-module-interface.swift +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %target-swift-ide-test -print-module -module-to-print=CanonicalTypes -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s - -// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { -// CHECK: var t: IntWrapper -// CHECK: init() -// CHECK: init(t: IntWrapper) -// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 -// CHECK: } -// CHECK: struct IntWrapper { -// CHECK: var value: Int32 -// CHECK: init() -// CHECK: mutating func getValue() -> Int32 -// CHECK: } -// CHECK: typealias WrappedMagicNumberA = __CxxTemplateInst12MagicWrapperI10IntWrapperE -// CHECK: typealias WrappedMagicNumberB = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/canonical-types.swift b/test/Interop/Cxx/templates/canonical-types.swift deleted file mode 100644 index b399e0fc9b144..0000000000000 --- a/test/Interop/Cxx/templates/canonical-types.swift +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import CanonicalTypes -import StdlibUnittest - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("canonical-types") { - // Different typedefs with the same C++ canonical type must have the same type from Swift's perspective as well. - expectEqualType(WrappedMagicNumberA.self, WrappedMagicNumberB.self) -} - -runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-including-members.swift b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift deleted file mode 100644 index 7d55595d4fbb4..0000000000000 --- a/test/Interop/Cxx/templates/decl-with-definition-including-members.swift +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import DeclWithDefinitionIncludingMembers -import StdlibUnittest - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("fully-defined") { - let myInt = IntWrapper(value: 10) - var magicInt = FullyDefinedMagicallyWrappedInt(t: myInt) - expectEqual(magicInt.getValuePlusArg(5), 15) -} - -runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift deleted file mode 100644 index 34825a34ce7e4..0000000000000 --- a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift +++ /dev/null @@ -1,33 +0,0 @@ -// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s - -import DeclWithDefinition - -public func getWrappedMagicInt() -> CInt { - let myInt = IntWrapper(value: 7) - var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) - return magicInt.getValuePlusArg(13) -} - -// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main18getWrappedMagicInts5Int32VyF"() -// CHECK: %magicInt = alloca %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, align 4 -// CHECK: %magicInt.t = getelementptr inbounds %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt, i32 0, i32 0 -// CHECK: [[MAGIC_WRAPPER:%.*]] = bitcast %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt to %struct.MagicWrapper* -// CHECK: call i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* [[MAGIC_WRAPPER]], i32 13) - -// CHECK: define weak_odr{{( dso_local)?}} i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* %this, i32 %arg) -// CHECK: %this.addr = alloca %struct.MagicWrapper*, align {{4|8}} -// CHECK: store %struct.MagicWrapper* %this, %struct.MagicWrapper** %this.addr, align {{4|8}} -// CHECK: %this1 = load %struct.MagicWrapper*, %struct.MagicWrapper** %this.addr, align {{4|8}} -// CHECK: %t = getelementptr inbounds %struct.MagicWrapper, %struct.MagicWrapper* %this1, i32 0, i32 0 -// CHECK: %call = call i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %t) -// CHECK: [[ARG:%.*]] = load i32, i32* %arg.addr, align 4 -// CHECK: %add = add nsw i32 %call, [[ARG]] -// CHECK: ret i32 %add - -// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %this) -// CHECK: %this.addr = alloca %struct.IntWrapper*, align {{4|8}} -// CHECK: store %struct.IntWrapper* %this, %struct.IntWrapper** %this.addr, align {{4|8}} -// CHECK: %this1 = load %struct.IntWrapper*, %struct.IntWrapper** %this.addr, align {{4|8}} -// CHECK: %value = getelementptr inbounds %struct.IntWrapper, %struct.IntWrapper* %this1, i32 0, i32 0 -// CHECK: [[VALUE:%.*]] = load i32, i32* %value, align 4 -// CHECK: ret i32 [[VALUE]] diff --git a/test/Interop/Cxx/templates/decl-with-definition-silgen.swift b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift deleted file mode 100644 index a9481f6ac9d6c..0000000000000 --- a/test/Interop/Cxx/templates/decl-with-definition-silgen.swift +++ /dev/null @@ -1,21 +0,0 @@ -// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s - -import DeclWithDefinition - -public func getWrappedMagicInt() -> CInt { - let myInt = IntWrapper(value: 21) - var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) - return magicInt.getValuePlusArg(32) -} - -// CHECK: // getWrappedMagicInt() -// CHECK: sil @$s4main18getWrappedMagicInts5Int32VyF : $@convention(thin) () -> Int32 { -// CHECK: [[INT_WRAPPER:%.*]] = struct $IntWrapper ([[_:%.*]] : $Int32) -// CHECK: [[_:%.*]] = struct $__CxxTemplateInst12MagicWrapperI10IntWrapperE ([[INT_WRAPPER]] : $IntWrapper) -// CHECK: // function_ref {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} -// CHECK: [[_:%.*]] = function_ref @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 - -// CHECK: // {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} -// CHECK: MagicWrapper::getValuePlusArg - -// CHECK: sil [clang __CxxTemplateInst12MagicWrapperI10IntWrapperE.getValuePlusArg] @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 diff --git a/test/Interop/Cxx/templates/decl-with-definition.swift b/test/Interop/Cxx/templates/decl-with-definition.swift deleted file mode 100644 index ce0841c4b9c9b..0000000000000 --- a/test/Interop/Cxx/templates/decl-with-definition.swift +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import DeclWithDefinition -import StdlibUnittest - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("has-partial-definition") { - let myInt = IntWrapper(value: 32) - var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) - expectEqual(magicInt.getValuePlusArg(5), 37) -} - -runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-primitive-argument.swift b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift deleted file mode 100644 index a2d5d1f8c9b98..0000000000000 --- a/test/Interop/Cxx/templates/decl-with-primitive-argument.swift +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import DeclWithPrimitiveArgument -import StdlibUnittest - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("int-argument") { - var wrappedMagicInt = WrappedMagicInt(t: 42) - expectEqual(wrappedMagicInt.getValuePlusArg(5), 47) -} - -runAllTests() diff --git a/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift deleted file mode 100644 index ca12841f96cb9..0000000000000 --- a/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %target-swift-ide-test -print-module -module-to-print=DeclWithoutDefinition -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s - -// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { -// CHECK: var t: IntWrapper -// CHECK: init() -// CHECK: init(t: IntWrapper) -// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 -// CHECK: } -// CHECK: struct IntWrapper { -// CHECK: var value: Int32 -// CHECK: init() -// CHECK: init(value: Int32) -// CHECK: mutating func getValue() -> Int32 -// CHECK: } -// CHECK: typealias MagicallyWrappedIntWithoutDefinition = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/decl-without-definition.swift b/test/Interop/Cxx/templates/decl-without-definition.swift deleted file mode 100644 index ef97376176ed4..0000000000000 --- a/test/Interop/Cxx/templates/decl-without-definition.swift +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import DeclWithoutDefinition -import StdlibUnittest - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("without-definition") { - let myInt = IntWrapper(value: 17) - var magicInt = MagicallyWrappedIntWithoutDefinition(t: myInt) - expectEqual(magicInt.getValuePlusArg(11), 28) -} - -runAllTests() diff --git a/test/Interop/Cxx/templates/demangling.swift b/test/Interop/Cxx/templates/demangling.swift deleted file mode 100644 index ac1e44efefe83..0000000000000 --- a/test/Interop/Cxx/templates/demangling.swift +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | grep 'define.*swiftcc.*$' | grep -o '\$[[:alnum:]]\+__CxxTemplateInst[[:alnum:]]\+' | xargs %swift-demangle | %FileCheck %s - -import Mangling - -public func receiveInstantiation(_ i: inout WrappedMagicInt) {} - -public func returnInstantiation() -> WrappedMagicInt { - return WrappedMagicInt() -} - -// CHECK: $s10demangling20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF ---> demangling.receiveInstantiation(inout __C.__CxxTemplateInst12MagicWrapperIiE) -> () -// CHECK: $s10demangling19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF ---> demangling.returnInstantiation() -> __C.__CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/eager-instatiation-problems.swift b/test/Interop/Cxx/templates/eager-instatiation-problems.swift deleted file mode 100644 index b2520b5b78275..0000000000000 --- a/test/Interop/Cxx/templates/eager-instatiation-problems.swift +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import EagerInstantiationProblems -import StdlibUnittest - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("eager-instantiation-of-members") { - // This will fail with: - // - // error: type 'int' cannot be used prior to '::' because it has no members - // T::getIntDoesNotExist(); - // - // whereas in C++ this compiles. This is caused by ClangImporter eagerly - // instantiating typedeffed templates and also their members. - // TODO(scentini): Fix this - // let _brokenMagicWrapper = BrokenMagicWrapper() -} - -TemplatesTestSuite.test("sfinae-example") { - // This will fail since we are currently not instantiating function templates. - // In C++ the first sfinaeGetInt should fail to instantiate, therefore get - // ignored, and only the second sfinaeGetInt is used. - // TODO(SR-12541): Fix this - // let magicNumber = MagicNumber() - // var brokenMagicWrapper = BrokenMagicWrapper() - // expectEqual(42, brokenMagicWrapper.sfinaeGetInt(magicNumber, 0)) -} - -runAllTests() diff --git a/test/Interop/Cxx/templates/explicit-specialization.swift b/test/Interop/Cxx/templates/explicit-specialization.swift deleted file mode 100644 index 58cb0c4d6746d..0000000000000 --- a/test/Interop/Cxx/templates/explicit-specialization.swift +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import ExplicitSpecialization -import StdlibUnittest - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("explicit-specialization") { - let specializedInt = SpecializedIntWrapper(value: 7) - var specializedMagicInt = WrapperWithSpecialization(t: specializedInt) - expectEqual(specializedMagicInt.doubleIfSpecializedElseTriple(), 14) - - let nonSpecializedInt = NonSpecializedIntWrapper(value: 7) - var nonSpecializedMagicInt = WrapperWithoutSpecialization(t: nonSpecializedInt) - expectEqual(nonSpecializedMagicInt.doubleIfSpecializedElseTriple(), 21) -} - -runAllTests() diff --git a/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift deleted file mode 100644 index f3a2ae75d69ba..0000000000000 --- a/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s - -import LinkageOfSwiftSymbolsForImportedTypes - -public func forceValueWitnessTableCreation() -> Any { - let magicNumber = MagicNumber() - return WrappedMagicNumber(t: magicNumber) -} - -public func getMagicNumberForLinkageComparison() -> Any { - return MagicNumber() -} - -// CHECK: $sSo11MagicNumberVWV" = linkonce_odr hidden constant -// CHECK: $sSo11MagicNumberVMn" = linkonce_odr hidden constant -// CHECK: $sSo11MagicNumberVMf" = linkonce_odr hidden constant -// CHECK: $sSo11MagicNumberVML" = linkonce_odr hidden global - -// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVWV" = linkonce_odr hidden constant -// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMn" = linkonce_odr hidden constant -// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMf" = linkonce_odr hidden constant -// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVML" = linkonce_odr hidden global - -// CHECK: $sSo11MagicNumberVMB" = linkonce_odr hidden constant -// CHECK: $sSo11MagicNumberVMF" = linkonce_odr hidden constant - -// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMB" = linkonce_odr hidden constant -// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMF" = linkonce_odr hidden constant diff --git a/test/Interop/Cxx/templates/mangling-irgen.swift b/test/Interop/Cxx/templates/mangling-irgen.swift deleted file mode 100644 index 363e1a3e76800..0000000000000 --- a/test/Interop/Cxx/templates/mangling-irgen.swift +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s - -import Mangling - -public func receiveInstantiation(_ i: inout WrappedMagicInt) {} - -// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIiEV* nocapture dereferenceable(1) %0) - -public func receiveInstantiation(_ i: inout WrappedMagicBool) {} - -// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIbEV* nocapture dereferenceable(1) %0) - -public func returnInstantiation() -> WrappedMagicInt { - return WrappedMagicInt() -} - -// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF"() - diff --git a/test/Interop/Cxx/templates/mangling-silgen.swift b/test/Interop/Cxx/templates/mangling-silgen.swift deleted file mode 100644 index 7d4cc6f7e3c39..0000000000000 --- a/test/Interop/Cxx/templates/mangling-silgen.swift +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s - -import Mangling - -public func recvInstantiation(_ i: inout WrappedMagicInt) {} - -// CHECK: // recvInstantiation(_:) -// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIiE) -> () - -public func recvInstantiation(_ i: inout WrappedMagicBool) {} - -// CHECK: // recvInstantiation(_:) -// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIbE) -> () - -public func returnInstantiation() -> WrappedMagicInt { - return WrappedMagicInt() -} - -// CHECK: // returnInstantiation() -// CHECK: sil @$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF : $@convention(thin) () -> __CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/using-directive-module-interface.swift b/test/Interop/Cxx/templates/using-directive-module-interface.swift deleted file mode 100644 index 81b445d21e3d7..0000000000000 --- a/test/Interop/Cxx/templates/using-directive-module-interface.swift +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %target-swift-ide-test -print-module -module-to-print=UsingDirective -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s - -// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { -// CHECK: var t: IntWrapper -// CHECK: init() -// CHECK: init(t: IntWrapper) -// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 -// CHECK: } -// CHECK: struct IntWrapper { -// CHECK: var value: Int32 -// CHECK: init() -// CHECK: init(value: Int32) -// CHECK: mutating func getValue() -> Int32 -// CHECK: } -// CHECK: typealias UsingWrappedMagicNumber = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/using-directive.swift b/test/Interop/Cxx/templates/using-directive.swift deleted file mode 100644 index 7f9c983fee834..0000000000000 --- a/test/Interop/Cxx/templates/using-directive.swift +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) -// -// REQUIRES: executable_test - -import StdlibUnittest -import UsingDirective - -var TemplatesTestSuite = TestSuite("TemplatesTestSuite") - -TemplatesTestSuite.test("using-directive") { - let myInt = IntWrapper(value: 333) - var magicInt = UsingWrappedMagicNumber(t: myInt) - expectEqual(magicInt.getValuePlusArg(111), 444) -} - -runAllTests() diff --git a/test/lit.cfg b/test/lit.cfg index 27c40a1cb6764..e8a4a36443fbf 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -282,7 +282,6 @@ config.sourcekitd_test = inferSwiftBinary('sourcekitd-test') config.complete_test = inferSwiftBinary('complete-test') config.swift_api_digester = inferSwiftBinary('swift-api-digester') config.swift_refactor = inferSwiftBinary('swift-refactor') -config.swift_demangle = inferSwiftBinary('swift-demangle') config.swift_demangle_yamldump = inferSwiftBinary('swift-demangle-yamldump') config.benchmark_o = inferSwiftBinary('Benchmark_O') config.benchmark_driver = inferSwiftBinary('Benchmark_Driver') @@ -440,7 +439,6 @@ config.substitutions.append( ('%llvm-dwarfdump', config.llvm_dwarfdump) ) config.substitutions.append( ('%llvm-readelf', config.llvm_readelf) ) config.substitutions.append( ('%llvm-dis', config.llvm_dis) ) config.substitutions.append( ('%llvm-nm', config.llvm_nm) ) -config.substitutions.append( ('%swift-demangle', config.swift_demangle) ) config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_yamldump) ) config.substitutions.append( ('%Benchmark_O', config.benchmark_o) ) config.substitutions.append( ('%Benchmark_Driver', config.benchmark_driver) ) From 8a39c8d9d825814ad90997bea15e533aa81908c5 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 11 Aug 2020 17:19:06 -0700 Subject: [PATCH 099/663] [CodeCompletion Remember the replaced source range in SourceManager --- include/swift/Basic/SourceManager.h | 17 +++++++++++++++++ lib/IDE/CompletionInstance.cpp | 1 + 2 files changed, 18 insertions(+) diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index e26e44e78cef9..a12aa169f7c51 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -38,6 +38,20 @@ class SourceManager { /// to speed up stats. mutable llvm::DenseMap StatusCache; + struct ReplacedRangeType { + SourceRange Original; + SourceRange New; + ReplacedRangeType() {} + ReplacedRangeType(NoneType) {} + ReplacedRangeType(SourceRange Original, SourceRange New) + : Original(Original), New(New) { + assert(Original.isValid() && New.isValid()); + } + + explicit operator bool() const { return Original.isValid(); } + }; + ReplacedRangeType ReplacedRange; + // \c #sourceLocation directive handling. struct VirtualFile { CharSourceRange Range; @@ -89,6 +103,9 @@ class SourceManager { SourceLoc getCodeCompletionLoc() const; + const ReplacedRangeType &getReplacedRange() const { return ReplacedRange; } + void setReplacedRange(const ReplacedRangeType &val) { ReplacedRange = val; } + /// Returns true if \c LHS is before \c RHS in the source buffer. bool isBeforeInBuffer(SourceLoc LHS, SourceLoc RHS) const { return LHS.Value.getPointer() < RHS.Value.getPointer(); diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 26842a4c21622..981560dbc8643 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -417,6 +417,7 @@ bool CompletionInstance::performCachedOperationIfPossible( auto *AFD = cast(DC); AFD->setBodyToBeReparsed(newBodyRange); + SM.setReplacedRange({AFD->getOriginalBodySourceRange(), newBodyRange}); traceDC = AFD; break; From 4ca3c232b7aa70b01b38dc2766fb5b7e23e295ce Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Wed, 12 Aug 2020 13:55:06 -0700 Subject: [PATCH 100/663] Fix LICM to avoid hoisting never-executed traps It is legal for the optimizer to consider code after a loop always reachable, but when a loop has no exits, or when the loops exits are dominated by a conditional statement, we should not consider conditional statements within the loop as dominating all possible execution paths through the loop. At least not when there is at least one path through the loop that contains a "synchronization point", such as a function that may contain a memory barrier, perform I/O, or exit the program. Sadly, we still don't model synchronization points in the optimizer, so we need to conservatively assume all loops have a synchronization point and avoid hoisting conditional traps that may never be executed. Fixes rdar://66791257 (Print statement provokes "Can't unsafeBitCast between types of different sizes" when optimizations enabled) Originated in 2014. --- include/swift/SIL/LoopInfo.h | 10 +++ lib/SILOptimizer/LoopTransforms/LICM.cpp | 6 +- test/SILOptimizer/licm.sil | 79 ++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/include/swift/SIL/LoopInfo.h b/include/swift/SIL/LoopInfo.h index 4bcdc47d253c6..200797c1a76d4 100644 --- a/include/swift/SIL/LoopInfo.h +++ b/include/swift/SIL/LoopInfo.h @@ -50,6 +50,16 @@ class SILLoop : public llvm::LoopBase { /// this loop by unrolling or versioning. bool canDuplicate(SILInstruction *Inst) const; + void getExitingAndLatchBlocks( + SmallVectorImpl &ExitingAndLatchBlocks) const { + this->getExitingBlocks(ExitingAndLatchBlocks); + SILBasicBlock *header = getHeader(); + for (auto *predBB : header->getPredecessorBlocks()) { + if (contains(predBB) && !this->isLoopExiting(predBB)) + ExitingAndLatchBlocks.push_back(predBB); + } + } + private: friend class llvm::LoopInfoBase; diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index e4be5ac35f5fa..69a0f32be343d 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -214,8 +214,8 @@ static void getDominatingBlocks(SmallVectorImpl &domBlocks, SILLoop *Loop, DominanceInfo *DT) { auto HeaderBB = Loop->getHeader(); auto DTRoot = DT->getNode(HeaderBB); - SmallVector ExitingBBs; - Loop->getExitingBlocks(ExitingBBs); + SmallVector ExitingAndLatchBBs; + Loop->getExitingAndLatchBlocks(ExitingAndLatchBBs); for (llvm::df_iterator It = llvm::df_begin(DTRoot), E = llvm::df_end(DTRoot); It != E;) { @@ -223,7 +223,7 @@ static void getDominatingBlocks(SmallVectorImpl &domBlocks, // Don't decent into control-dependent code. Only traverse into basic blocks // that dominate all exits. - if (!std::all_of(ExitingBBs.begin(), ExitingBBs.end(), + if (!std::all_of(ExitingAndLatchBBs.begin(), ExitingAndLatchBBs.end(), [=](SILBasicBlock *ExitBB) { return DT->dominates(CurBB, ExitBB); })) { diff --git a/test/SILOptimizer/licm.sil b/test/SILOptimizer/licm.sil index 6823dda54a085..9ac8ae2492cba 100644 --- a/test/SILOptimizer/licm.sil +++ b/test/SILOptimizer/licm.sil @@ -854,3 +854,82 @@ bb9(%39 : $Builtin.Int64): // Preds: bb7 dealloc_stack %3 : $*Index // id: %41 return %40 : $Int64 // id: %42 } + +// testConditionalTrapInInfiniteSyncLoop and +// testConditionalTrapDominatingSyncLoopExit +// +// It's legal for the optimizer to consider code after the loop as +// always reachable, but when a loop has no exits, or when the loops +// exits are dominated by a conditional statement we should not +// consider conditional statements within the loop as dominating all +// possible execution paths through the loop. At least not when there +// is at least one path through the loop that contains a +// "synchronization point", such as a function that may contain a +// memory barrier, perform I/O, or exit the program. +sil @mayExit : $@convention(thin) () -> () + +// CHECK-LABEL: sil @testConditionalTrapInInfiniteSyncLoop : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { +// CHECK: bb0 +// CHECK-NOT: cond_fail +// CHECK: br bb1 +// CHECK: bb1: +// CHECK: cond_br %0, bb2, bb3 +// CHECK: bb2: +// CHECK: cond_fail %1 : $Builtin.Int1, "arithmetic overflow" +// CHECK-LABEL: } // end sil function 'testConditionalTrapInInfiniteSyncLoop' +sil @testConditionalTrapInInfiniteSyncLoop : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { +bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1): + br bb1 + +bb1: // loop head + cond_br %0, bb2, bb3 + +bb2: // maybe never executed + cond_fail %1 : $Builtin.Int1, "arithmetic overflow" + br bb4 + +bb3: + // synchronization point: has "real" side-effects that we can't + // reorder with traps + %f = function_ref @mayExit : $@convention(thin) () -> () + apply %f() : $@convention(thin) () -> () + br bb4 + +bb4: // latch + br bb1 +} + +// CHECK-LABEL: sil @testConditionalTrapDominatingSyncLoopExit : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () { +// CHECK: bb0 +// CHECK-NOT: cond_fail +// CHECK: br bb1 +// CHECK: bb1: +// CHECK: cond_br %0, bb2, bb4 +// CHECK: bb2: +// CHECK: cond_fail %1 : $Builtin.Int1, "arithmetic overflow" +// CHECK-LABEL: } // end sil function 'testConditionalTrapDominatingSyncLoopExit' +sil @testConditionalTrapDominatingSyncLoopExit : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () { +bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1, %2 : $Builtin.Int1): + br bb1 + +bb1: // loop head + cond_br %0, bb2, bb4 + +bb2: // maybe never executed + cond_fail %1 : $Builtin.Int1, "arithmetic overflow" + cond_br %2, bb3, bb5 + +bb3: // tail + br bb1 + +bb4: + // synchronization point: has "real" side-effects that we can't + // reorder with traps + %f = function_ref @mayExit : $@convention(thin) () -> () + apply %f() : $@convention(thin) () -> () + br bb1 + +bb5: + %99 = tuple () + return %99 : $() +} From 2a8e4b2d49c95ae1d8d5273c229df2661d2d6a38 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 12 Aug 2020 12:41:20 -0700 Subject: [PATCH 101/663] Add IRGen test for Explicit Module Build with a framework dependency. Ensures auto-linking commands are issued for the framework import module. --- .../explicit-framework-irgen.swift | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 test/ScanDependencies/explicit-framework-irgen.swift diff --git a/test/ScanDependencies/explicit-framework-irgen.swift b/test/ScanDependencies/explicit-framework-irgen.swift new file mode 100644 index 0000000000000..516b2a3f74855 --- /dev/null +++ b/test/ScanDependencies/explicit-framework-irgen.swift @@ -0,0 +1,37 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/inputs +// RUN: echo "/// Some cool comments" > %t/foo.swift +// RUN: echo "public func foo() {}" >> %t/foo.swift +// RUN: %target-swift-frontend -emit-module -emit-module-path %t/inputs/Foo.swiftmodule -emit-module-doc-path %t/inputs/Foo.swiftdoc -emit-module-source-info -emit-module-source-info-path %t/inputs/Foo.swiftsourceinfo -module-cache-path %t.module-cache %t/foo.swift -module-name Foo + +// RUN: echo "[{" > %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Foo\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/t/inputs/Foo.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"docPath\": \"%/t/inputs/Foo.swiftdoc\"," >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/Foo.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": true" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}]" >> %/t/inputs/map.json + +// RUN: %target-swift-frontend -emit-object -emit-module -disable-implicit-swift-modules -explicit-swift-module-map-file %t/inputs/map.json -o %t/explicit-framework-irgen.o %s +import Foo + +// This test is to verify autolinking behavior so it is macOS-specific. +// REQUIRES OS=macosx + +// RUN: otool -l %t/explicit-framework-irgen.o | %FileCheck %s +// CHECK: cmd LC_LINKER_OPTION +// CHECK-NEXT: cmdsize 32 +// CHECK-NEXT: count 2 +// CHECK-NEXT: string #1 -framework +// CHECK-NEXT: string #2 Foo From 7d3d4de65b0863270c7391e419fd842a6181c25d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 12 Aug 2020 14:39:56 -0700 Subject: [PATCH 102/663] Fixup IdentifierInfo Key Confusion Clang has two sources of IdentifierInfo pointers: the ASTContext and the Preprocessor. Even though the keys from each can be used to index into the other's tables, doing so has detrimental effects on the Clang Importer. At the very least, it will cause the Clang Importer to re-load modules that should have already been cached down by implicit module builds. This is because the module will build itself against a properly interned key from the Preprocessor, but be looked up by a key from the ASTContext after the next time. Once in a blue moon, this may even allow Clang to return garbage to us, though I'm still verifying that. For now, let's patch up this mess by using the right source of keys. --- lib/ClangImporter/ClangImporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 357f8000617d4..74a7e4f17fe8e 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -1714,7 +1714,6 @@ bool ClangImporter::canImportModule(Located moduleID) { ModuleDecl *ClangImporter::Implementation::loadModuleClang( SourceLoc importLoc, ArrayRef> path) { - auto &clangContext = getClangASTContext(); auto &clangHeaderSearch = getClangPreprocessor().getHeaderSearchInfo(); // Look up the top-level module first, to see if it exists at all. @@ -1728,8 +1727,9 @@ ModuleDecl *ClangImporter::Implementation::loadModuleClang( SmallVector, 4> clangPath; for (auto component : path) { - clangPath.push_back({&clangContext.Idents.get(component.Item.str()), - exportSourceLoc(component.Loc)}); + clangPath.emplace_back( + getClangPreprocessor().getIdentifierInfo(component.Item.str()), + exportSourceLoc(component.Loc)); } auto &rawDiagClient = Instance->getDiagnosticClient(); From ce77651b32f8a91e3457770a6fddfd88465147d3 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Wed, 12 Aug 2020 15:21:17 -0700 Subject: [PATCH 103/663] [ConstraintLocator] Always store the PathElementKind in each path element. --- lib/Sema/ConstraintLocator.h | 105 +++++++++++------------------------ 1 file changed, 31 insertions(+), 74 deletions(-) diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 0c3c3e1a432ce..85bb04eeff927 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -122,23 +122,19 @@ class ConstraintLocator : public llvm::FoldingSetNode { class PathElement { /// Describes the kind of data stored here. enum StoredKind : unsigned char { - StoredGenericParameter, - StoredProtocolRequirement, - StoredWitness, - StoredGenericSignature, - StoredKeyPathDynamicMemberBase, - StoredPattern, - StoredKindAndValue + StoredPointer, + StoredInteger, }; + PathElementKind kind; + /// The actual storage for the path element, which involves both a - /// kind and (potentially) a value. + /// storage kind and a value. /// - /// The current storage involves a two-bit "storage kind", which selects - /// among the possible value stores. The value stores can either be an - /// archetype (for archetype path elements) or an unsigned value that - /// stores both the specific kind and the (optional) numeric value of that - /// kind. Use \c encodeStorage and \c decodeStorage to work with this value. + /// The current storage involves a three-bit "storage kind", which selects + /// among the possible value stores. The value stores can either be a + /// pointer or an unsigned int. Use \c getValue or \c getStoredPointer + /// to work with this value. /// /// \note The "storage kind" is stored in the \c storedKind field. uint64_t storage : 61; @@ -147,17 +143,6 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// from the StoredKind enum. uint64_t storedKind : 3; - /// Encode a path element kind and a value into the storage format. - static uint64_t encodeStorage(PathElementKind kind, uint64_t value) { - return (value << 8) | kind; - } - - /// Decode a storage value into path element kind and value. - static std::pair - decodeStorage(uint64_t storage) { - return { (PathElementKind)((unsigned)storage & 0xFF), storage >> 8 }; - } - /// Retrieve a value associated with the path element. unsigned getValue(unsigned index) const { unsigned numValues = numNumericValuesInPathElement(getKind()); @@ -167,12 +152,12 @@ class ConstraintLocator : public llvm::FoldingSetNode { // being stored in the upper bits, valueN in the lower bits. Therefore we // need to shift out any extra values in the lower bits. auto extraValues = numValues - index - 1; - auto value = decodeStorage(storage).second >> (extraValues * 16); + auto value = storage >> (extraValues * 16); return value & 0xFFFF; } PathElement(PathElementKind kind, unsigned value) - : storage(encodeStorage(kind, value)), storedKind(StoredKindAndValue) + : kind(kind), storage(value), storedKind(StoredInteger) { assert(numNumericValuesInPathElement(kind) == 1 && "Path element kind does not require 1 value"); @@ -180,8 +165,8 @@ class ConstraintLocator : public llvm::FoldingSetNode { } PathElement(PathElementKind kind, unsigned value0, unsigned value1) - : storage(encodeStorage(kind, value0 << 16 | value1)), - storedKind(StoredKindAndValue) + : kind(kind), storage(value0 << 16 | value1), + storedKind(StoredInteger) { assert(numNumericValuesInPathElement(kind) == 2 && "Path element kind does not require 2 values"); @@ -189,10 +174,9 @@ class ConstraintLocator : public llvm::FoldingSetNode { assert(value1 == getValue(1) && "value1 truncated"); } - PathElement(PathElementKind kind, uint64_t value0, uint64_t value1, - uint64_t value2) - : storage(encodeStorage(kind, value0 << 32 | value1 << 16 | value2)), - storedKind(StoredKindAndValue) { + PathElement(PathElementKind kind, uint64_t value0, uint64_t value1, uint64_t value2) + : kind(kind), storage(value0 << 32 | value1 << 16 | value2), + storedKind(StoredInteger) { assert(numNumericValuesInPathElement(kind) == 3 && "Path element kind does not require 3 values"); assert(value0 == getValue(0) && "value0 truncated"); @@ -203,9 +187,9 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// Store a path element with an associated pointer, accessible using /// \c getStoredPointer. template - PathElement(StoredKind storedKind, T *ptr) - : storage((reinterpret_cast(ptr) >> 3)), - storedKind(storedKind) { + PathElement(PathElementKind kind, T *ptr) + : kind(kind), storage((reinterpret_cast(ptr) >> 3)), + storedKind(StoredPointer) { assert(ptr == getStoredPointer()); } @@ -213,7 +197,7 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// the type used when creating the path element. template T *getStoredPointer() const { - assert(storedKind != StoredKindAndValue); + assert(storedKind == StoredPointer); return reinterpret_cast(storage << 3); } @@ -224,39 +208,14 @@ class ConstraintLocator : public llvm::FoldingSetNode { #include "ConstraintLocatorPathElts.def" PathElement(PathElementKind kind) - : storage(encodeStorage(kind, 0)), storedKind(StoredKindAndValue) + : kind(kind), storage(0), storedKind(StoredInteger) { assert(numNumericValuesInPathElement(kind) == 0 && "Path element requires value"); } /// Retrieve the kind of path element. - PathElementKind getKind() const { - switch (static_cast(storedKind)) { - case StoredGenericParameter: - return PathElementKind::GenericParameter; - - case StoredProtocolRequirement: - return PathElementKind::ProtocolRequirement; - - case StoredWitness: - return PathElementKind::Witness; - - case StoredGenericSignature: - return PathElementKind::OpenedGeneric; - - case StoredKeyPathDynamicMemberBase: - return PathElementKind::KeyPathDynamicMember; - - case StoredPattern: - return PathElementKind::PatternMatch; - - case StoredKindAndValue: - return decodeStorage(storage).first; - } - - llvm_unreachable("Unhandled StoredKind in switch."); - } + PathElementKind getKind() const { return kind; } /// Attempts to cast the path element to a specific \c LocatorPathElt /// subclass, returning \c None if unsuccessful. @@ -765,31 +724,31 @@ class LocatorPathElt::ContextualType final : public LocatorPathElt { class LocatorPathElt::Witness final : public LocatorPathElt { public: Witness(ValueDecl *witness) - : LocatorPathElt(LocatorPathElt::StoredWitness, witness) {} + : LocatorPathElt(PathElementKind::Witness, witness) {} ValueDecl *getDecl() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { - return elt->getKind() == ConstraintLocator::Witness; + return elt->getKind() == PathElementKind::Witness; } }; class LocatorPathElt::ProtocolRequirement final : public LocatorPathElt { public: ProtocolRequirement(ValueDecl *decl) - : LocatorPathElt(LocatorPathElt::StoredProtocolRequirement, decl) {} + : LocatorPathElt(PathElementKind::ProtocolRequirement, decl) {} ValueDecl *getDecl() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { - return elt->getKind() == ConstraintLocator::ProtocolRequirement; + return elt->getKind() == PathElementKind::ProtocolRequirement; } }; class LocatorPathElt::GenericParameter final : public LocatorPathElt { public: GenericParameter(GenericTypeParamType *type) - : LocatorPathElt(LocatorPathElt::StoredGenericParameter, type) { + : LocatorPathElt(PathElementKind::GenericParameter, type) { static_assert(alignof(GenericTypeParamType) >= 4, "archetypes insufficiently aligned"); } @@ -799,15 +758,14 @@ class LocatorPathElt::GenericParameter final : public LocatorPathElt { } static bool classof(const LocatorPathElt *elt) { - return elt->getKind() == ConstraintLocator::GenericParameter; + return elt->getKind() == PathElementKind::GenericParameter; } }; class LocatorPathElt::OpenedGeneric final : public LocatorPathElt { public: OpenedGeneric(GenericSignature sig) - : LocatorPathElt(LocatorPathElt::StoredGenericSignature, - sig.getPointer()) {} + : LocatorPathElt(PathElementKind::OpenedGeneric, sig.getPointer()) {} GenericSignature getSignature() const { return getStoredPointer(); @@ -821,8 +779,7 @@ class LocatorPathElt::OpenedGeneric final : public LocatorPathElt { class LocatorPathElt::KeyPathDynamicMember final : public LocatorPathElt { public: KeyPathDynamicMember(NominalTypeDecl *keyPathDecl) - : LocatorPathElt(LocatorPathElt::StoredKeyPathDynamicMemberBase, - keyPathDecl) {} + : LocatorPathElt(PathElementKind::KeyPathDynamicMember, keyPathDecl) {} NominalTypeDecl *getKeyPathDecl() const { return getStoredPointer(); @@ -850,7 +807,7 @@ class LocatorPathElt::TernaryBranch final : public LocatorPathElt { class LocatorPathElt::PatternMatch final : public LocatorPathElt { public: PatternMatch(Pattern *pattern) - : LocatorPathElt(LocatorPathElt::StoredPattern, pattern) {} + : LocatorPathElt(PathElementKind::PatternMatch, pattern) {} Pattern *getPattern() const { return getStoredPointer(); } From 513fed7d8cb22acab5123ac42ff2c769ea528300 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 11 Aug 2020 22:42:22 -0700 Subject: [PATCH 104/663] [CodeCompletion] Enable ASTScope in code completion * Re-create `ASTScope` for each completion * Add generic params and where clause scope even without missing body * Use `getOriginalBodySourceRange()` for `AbstractFunctionBodyScope` * Source range translations for replaced ranges when finding scopes * Bypass source range checks when the completion happens in the replaced range * Be lenient with ASTScope / DeclContext mismatch in code completion --- include/swift/AST/SourceFile.h | 6 ++++- lib/AST/ASTScopeCreation.cpp | 13 ++++----- lib/AST/ASTScopeLookup.cpp | 43 +++++++++++++++++++++++------- lib/AST/ASTScopeSourceRange.cpp | 22 ++++++++++++--- lib/AST/Module.cpp | 2 +- lib/IDE/CompletionInstance.cpp | 4 +-- test/IDE/complete_attributes.swift | 21 +++++++++++++++ 7 files changed, 87 insertions(+), 24 deletions(-) diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index ca305f8675db8..96c25e4ab5ae1 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -172,7 +172,7 @@ class SourceFile final : public FileUnit { bool IsPrimary; /// The scope map that describes this source file. - std::unique_ptr Scope; + NullablePtr Scope = nullptr; /// The set of validated opaque return type decls in the source file. llvm::SmallVector OpaqueReturnTypes; @@ -468,6 +468,10 @@ class SourceFile final : public FileUnit { /// Retrieve the scope that describes this source file. ASTScope &getScope(); + void clearScope() { + Scope = nullptr; + } + /// Retrieves the previously set delayed parser state, asserting that it /// exists. PersistentParserState *getDelayedParserState() { diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index e2b30ed302bb6..6c1336d48d9e2 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -795,7 +795,7 @@ void ASTSourceFileScope:: void ASTSourceFileScope::expandFunctionBody(AbstractFunctionDecl *AFD) { if (!AFD) return; - auto sr = AFD->getBodySourceRange(); + auto sr = AFD->getOriginalBodySourceRange(); if (sr.isInvalid()) return; ASTScopeImpl *bodyScope = findInnermostEnclosingScope(sr.Start, nullptr); @@ -1596,11 +1596,6 @@ ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope( // Get now in case recursion emancipates scope auto *const ip = scope->getParent().get(); - // Prevent circular request bugs caused by illegal input and - // doing lookups that getExtendedNominal in the midst of getExtendedNominal. - if (scope->shouldHaveABody() && !scope->doesDeclHaveABody()) - return ip; - auto *context = scope->getGenericContext(); auto *genericParams = (isa(context) ? context->getParsedGenericParams() @@ -1609,6 +1604,12 @@ ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope( scope->getDecl(), genericParams, scope); if (context->getTrailingWhereClause()) scope->createTrailingWhereClauseScope(deepestScope, scopeCreator); + + // Prevent circular request bugs caused by illegal input and + // doing lookups that getExtendedNominal in the midst of getExtendedNominal. + if (scope->shouldHaveABody() && !scope->doesDeclHaveABody()) + return ip; + scope->createBodyScope(deepestScope, scopeCreator); return ip; } diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 13ab5b86a3177..b507343592abf 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -82,6 +82,15 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( // Someday, just use the assertion below. For now, print out lots of info for // debugging. if (!startingScope) { + + // Be lenient in code completion mode. There are cases where the decl + // context doesn't match with the ASTScope. e.g. dangling attributes. + // FIXME: Create ASTScope tree even for invalid code. + if (innermost && + startingContext->getASTContext().SourceMgr.hasCodeCompletionBuffer()) { + return innermost; + } + llvm::errs() << "ASTScopeImpl: resorting to startingScope hack, file: " << sourceFile->getFilename() << "\n"; // The check is costly, and inactive lookups will end up here, so don't @@ -143,6 +152,20 @@ bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const { return true; } +/// If the \p loc is in a new buffer but \p range is not, consider the location +/// is at the start of replaced range. Otherwise, returns \p loc as is. +static SourceLoc translateLocForReplacedRange(SourceManager &sourceMgr, + SourceRange range, + SourceLoc loc) { + if (const auto &replacedRange = sourceMgr.getReplacedRange()) { + if (sourceMgr.rangeContainsTokenLoc(replacedRange.New, loc) && + !sourceMgr.rangeContains(replacedRange.New, range)) { + return replacedRange.Original.Start; + } + } + return loc; +} + NullablePtr ASTScopeImpl::findChildContaining(SourceLoc loc, SourceManager &sourceMgr) const { @@ -152,24 +175,24 @@ ASTScopeImpl::findChildContaining(SourceLoc loc, bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); - return -1 == ASTScopeImpl::compare(scope->getSourceRangeOfScope(), loc, - sourceMgr, + auto rangeOfScope = scope->getSourceRangeOfScope(); + loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); + return -1 == ASTScopeImpl::compare(rangeOfScope, loc, sourceMgr, /*ensureDisjoint=*/false); } bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); - // Alternatively, we could check that loc < start-of-scope - return 0 >= ASTScopeImpl::compare(loc, scope->getSourceRangeOfScope(), - sourceMgr, - /*ensureDisjoint=*/false); + return !(*this)(scope, loc); } }; auto *const *child = std::lower_bound( getChildren().begin(), getChildren().end(), loc, CompareLocs{sourceMgr}); - if (child != getChildren().end() && - sourceMgr.rangeContainsTokenLoc((*child)->getSourceRangeOfScope(), loc)) - return *child; + if (child != getChildren().end()) { + auto rangeOfScope = (*child)->getSourceRangeOfScope(); + loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); + if (sourceMgr.rangeContainsTokenLoc(rangeOfScope, loc)) + return *child; + } return nullptr; } diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 731826ad5f6a3..cecd970590cc6 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -67,6 +67,14 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, if (range.isInvalid()) return childRange; auto r = range; + + // HACK: For code completion. If the range of the child is from another + // source buffer, don't widen using that range. + if (const auto &replacedRange = getSourceManager().getReplacedRange()) { + if (getSourceManager().rangeContains(replacedRange.Original, range) && + getSourceManager().rangeContains(replacedRange.New, childRange)) + return r; + } r.widen(childRange); return r; } @@ -114,6 +122,14 @@ bool ASTScopeImpl::verifyThatChildrenAreContainedWithin( getChildren().back()->getSourceRangeOfScope().End); if (getSourceManager().rangeContains(range, rangeOfChildren)) return true; + + // HACK: For code completion. Handle replaced range. + if (const auto &replacedRange = getSourceManager().getReplacedRange()) { + if (getSourceManager().rangeContains(replacedRange.Original, range) && + getSourceManager().rangeContains(replacedRange.New, rangeOfChildren)) + return true; + } + auto &out = verificationError() << "children not contained in its parent\n"; if (getChildren().size() == 1) { out << "\n***Only Child node***\n"; @@ -200,7 +216,7 @@ SourceRange DifferentiableAttributeScope::getSourceRangeOfThisASTNode( SourceRange AbstractFunctionBodyScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { - return decl->getBodySourceRange(); + return decl->getOriginalBodySourceRange(); } SourceRange TopLevelCodeScope::getSourceRangeOfThisASTNode( @@ -357,7 +373,7 @@ SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); return r; } - return decl->getBodySourceRange(); + return decl->getOriginalBodySourceRange(); } SourceRange ParameterListScope::getSourceRangeOfThisASTNode( @@ -609,7 +625,7 @@ SourceRange IterableTypeScope::sourceRangeForDeferredExpansion() const { return portion->sourceRangeForDeferredExpansion(this); } SourceRange AbstractFunctionBodyScope::sourceRangeForDeferredExpansion() const { - const auto bsr = decl->getBodySourceRange(); + const auto bsr = decl->getOriginalBodySourceRange(); const SourceLoc endEvenIfNoCloseBraceAndEndsWithInterpolatedStringLiteral = getLocEncompassingPotentialLookups(getSourceManager(), bsr.End); return SourceRange(bsr.Start, diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 6749fdc8b8802..34a9d40705693 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2387,7 +2387,7 @@ StringRef SourceFile::getFilename() const { ASTScope &SourceFile::getScope() { if (!Scope) - Scope = std::unique_ptr(new (getASTContext()) ASTScope(this)); + Scope = new (getASTContext()) ASTScope(this); return *Scope.get(); } diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 981560dbc8643..54bcf8a8cc0ee 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -418,6 +418,7 @@ bool CompletionInstance::performCachedOperationIfPossible( auto *AFD = cast(DC); AFD->setBodyToBeReparsed(newBodyRange); SM.setReplacedRange({AFD->getOriginalBodySourceRange(), newBodyRange}); + oldSF->clearScope(); traceDC = AFD; break; @@ -603,9 +604,6 @@ bool swift::ide::CompletionInstance::performOperation( // We don't need token list. Invocation.getLangOptions().CollectParsedToken = false; - // FIXME: ASTScopeLookup doesn't support code completion yet. - Invocation.disableASTScopeLookup(); - if (EnableASTCaching) { // Compute the signature of the invocation. llvm::hash_code ArgsHash(0); diff --git a/test/IDE/complete_attributes.swift b/test/IDE/complete_attributes.swift index a1fa33e3a9bb9..e7b5d203500f9 100644 --- a/test/IDE/complete_attributes.swift +++ b/test/IDE/complete_attributes.swift @@ -1,5 +1,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_ATTR_1 -code-completion-keywords=false | %FileCheck %s -check-prefix=ERROR_COMMON // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=MEMBER_DECL_ATTR_1 -code-completion-keywords=false | %FileCheck %s -check-prefix=ERROR_COMMON +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ATTRARG_MEMBER | %FileCheck %s -check-prefix=MEMBER_MyValue +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ATTRARG_MEMBER_IN_CLOSURE | %FileCheck %s -check-prefix=MEMBER_MyValue // ERROR_COMMON: found code completion token // ERROR_COMMON-NOT: Keyword/ @@ -9,3 +11,22 @@ class MemberDeclAttribute { @#^MEMBER_DECL_ATTR_1^# func memberDeclAttr1() {} } + +struct MyValue { + init() {} + static var val: Int +} + +// MEMBER_MyValue: Begin completions, 4 items +// MEMBER_MyValue-DAG: Keyword[self]/CurrNominal: self[#MyValue.Type#]; +// MEMBER_MyValue-DAG: Keyword/CurrNominal: Type[#MyValue.Type#]; +// MEMBER_MyValue-DAG: Decl[Constructor]/CurrNominal: init()[#MyValue#]; +// MEMBER_MyValue-DAG: Decl[StaticVar]/CurrNominal: val[#Int#]; +// MEMBER_MyValue: End completions + +class TestUknownDanglingAttr1 { + @UknownAttr(arg: MyValue.#^ATTRARG_MEMBER^#) +} +class TestUknownDanglingAttr2 { + @UknownAttr(arg: { MyValue.#^ATTRARG_MEMBER_IN_CLOSURE^# }) +} From bc2085683f1621d1b9b34d72779fd2683a96604e Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 12 Aug 2020 16:36:16 -0700 Subject: [PATCH 105/663] [Test] Add a test case for extension where clause with missing body rdar://problem/66943328 --- test/decl/ext/extensions.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index 485ff4da476d7..6729bba8d1e07 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -349,3 +349,10 @@ struct SR_10466 { extension SR_10466 where T == Never { // expected-note {{requirement specified as 'T' == 'Never' [with T = T]}} typealias A = Int } + +#if true +protocol Rdar66943328 { + associatedtype Assoc +} +extension Rdar66943328 where Assoc == Int // expected-error {{expected '{' in extension}} +#endif From 878efac769392d4cdcdbd0eecefc74bd992badde Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 3 Aug 2020 18:20:36 +0900 Subject: [PATCH 106/663] [Serialization] Force destructor creation for imported class Swift class deinit decl can be implicitly synthesized when emitting swiftmodule, so swiftmodule always have deinit decl. So resolution of x-refs to deinit of swift class always success. But when x-refs points deinit of clang imported class, it always failed because clang importer doesn't force to synthesize deinit before looking up. x-refs to deinit decl appears in only deinit of its subclasses, so it's serialized only when deinit have body. And deinit has body only on SIB because deinit is always non-inlinable. It means that this missing of deinit creation can be problem only on SIB This commit changes to force to synthesize class deinit decl before looking up members. --- lib/Serialization/Deserialization.cpp | 8 ++++++++ test/Serialization/Inputs/objc-xref/module.modulemap | 4 ++++ test/Serialization/Inputs/objc-xref/objc_xref.h | 2 ++ test/Serialization/xref-deinit.swift | 9 +++++++++ 4 files changed, 23 insertions(+) create mode 100644 test/Serialization/Inputs/objc-xref/module.modulemap create mode 100644 test/Serialization/Inputs/objc-xref/objc_xref.h create mode 100644 test/Serialization/xref-deinit.swift diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 8197ba44e96e4..7dc8c247a1ab6 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1611,6 +1611,14 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { getXRefDeclNameForError()); } + if (memberName.getKind() == DeclBaseName::Kind::Destructor) { + assert(isa(nominal)); + // Force creation of an implicit destructor + auto CD = dyn_cast(nominal); + values.push_back(CD->getDestructor()); + break; + } + if (!privateDiscriminator.empty()) { ModuleDecl *searchModule = M; if (!searchModule) diff --git a/test/Serialization/Inputs/objc-xref/module.modulemap b/test/Serialization/Inputs/objc-xref/module.modulemap new file mode 100644 index 0000000000000..7c036997bed3b --- /dev/null +++ b/test/Serialization/Inputs/objc-xref/module.modulemap @@ -0,0 +1,4 @@ +module ObjCXRef { + header "objc_xref.h" + export * +} diff --git a/test/Serialization/Inputs/objc-xref/objc_xref.h b/test/Serialization/Inputs/objc-xref/objc_xref.h new file mode 100644 index 0000000000000..d3b7a87ef6439 --- /dev/null +++ b/test/Serialization/Inputs/objc-xref/objc_xref.h @@ -0,0 +1,2 @@ +@interface MyObject +@end diff --git a/test/Serialization/xref-deinit.swift b/test/Serialization/xref-deinit.swift new file mode 100644 index 0000000000000..98c43b6670a87 --- /dev/null +++ b/test/Serialization/xref-deinit.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib %s -o %t/xref-deinit.sib -I%t -I %S/Inputs/objc-xref +// RUN: %target-swift-frontend -emit-sil %t/xref-deinit.sib -I%t -I %S/Inputs/objc-xref + +// REQUIRES: objc_interop + +import ObjCXRef + +public class Object: MyObject {} From 665100d74fbde73b580c95a58ee1b98e0729a467 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 12 Aug 2020 17:04:41 -0700 Subject: [PATCH 107/663] [IRGen] Teach defineAlias to replace useds. Previously, it was possible to alias an old LinkEntity which was marked used (i.e. in LLVMUsed) or compiler used (i.e. in LLVMCompilerUsed). The result of defining such an alias was a failure downstream when writing out the lists of globals. Here, the old value is removed from the list before it is invalidated. --- lib/IRGen/GenDecl.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index b5fbcef362e4e..ab718f80c5173 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3853,6 +3853,19 @@ llvm::GlobalValue *IRGenModule::defineAlias(LinkEntity entity, if (entry) { auto existingVal = cast(entry); + for (auto iterator = std::begin(LLVMUsed); iterator < std::end(LLVMUsed); ++iterator) { + llvm::Value *thisValue = *iterator; + if (thisValue == existingVal) { + LLVMUsed.erase(iterator); + } + } + for (auto iterator = std::begin(LLVMCompilerUsed); iterator < std::end(LLVMCompilerUsed); ++iterator) { + llvm::Value *thisValue = *iterator; + if (thisValue == existingVal) { + LLVMCompilerUsed.erase(iterator); + } + } + // FIXME: MC breaks when emitting alias references on some platforms // (rdar://problem/22450593 ). Work around this by referring to the aliasee // instead. From 77c70e9fe69535670d722a8647248d48226db9e1 Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Mon, 10 Aug 2020 16:57:14 +1000 Subject: [PATCH 108/663] [SourceKit/CodeFormat] Indent lines in multi-line strings When the multi-line string is unterminated, the indentation of a line will be the same as the first previous line that had contents, unless that line is the line containing the start quotes. In that case the indentation will be: - the same as the start quote indentation, if the quotes are the only contents on the line, or - an extra indentation level to the start quote line otherwise Lines within a terminated multi-line string or lines with content will only ever be indented if their current indentation is invalid (ie. their indentation level is less than that of their end quotes). This rule is to prevent any signficant (and possibly unintended) whitespace being added to existing strings during a whole file/range format - Xcode does not remove whitespace from whitespace-only lines by default. This could be improved if the reformat was sent the actual range rather than a line at a time. Different indentation could then be chosen if the range was in fact a single line. Resolves rdar://32181422 --- lib/IDE/Formatting.cpp | 155 ++++++++++++++---- .../indent-multiline-string-interp.swift | 57 +++++++ .../indent-multiline-string-nested.swift | 25 +++ ...ent-multiline-string-trailing-interp.swift | 31 ++++ ...nt-multiline-string-trailing-ownline.swift | 24 +++ .../indent-multiline-string-trailing.swift | 23 +++ .../CodeFormat/indent-multiline-string.swift | 46 ++++-- 7 files changed, 322 insertions(+), 39 deletions(-) create mode 100644 test/SourceKit/CodeFormat/indent-multiline-string-interp.swift create mode 100644 test/SourceKit/CodeFormat/indent-multiline-string-nested.swift create mode 100644 test/SourceKit/CodeFormat/indent-multiline-string-trailing-interp.swift create mode 100644 test/SourceKit/CodeFormat/indent-multiline-string-trailing-ownline.swift create mode 100644 test/SourceKit/CodeFormat/indent-multiline-string-trailing.swift diff --git a/lib/IDE/Formatting.cpp b/lib/IDE/Formatting.cpp index 69b9fc92f4b7a..6100a21d41669 100644 --- a/lib/IDE/Formatting.cpp +++ b/lib/IDE/Formatting.cpp @@ -61,6 +61,13 @@ getLocForContentStartOnSameLine(SourceManager &SM, SourceLoc Loc) { return LineStart.getAdvancedLoc(Indentation.size()); } +/// \returns true if the line at \c Loc is either empty or only contains whitespace +static bool isLineAtLocEmpty(SourceManager &SM, SourceLoc Loc) { + SourceLoc LineStart = Lexer::getLocForStartOfLine(SM, Loc); + SourceLoc Next = Lexer::getTokenAtLocation(SM, LineStart, CommentRetentionMode::ReturnAsTokens).getLoc(); + return Next.isInvalid() || !isOnSameLine(SM, Loc, Next); +} + /// \returns the first token after the token at \c Loc. static Optional getTokenAfter(SourceManager &SM, SourceLoc Loc, bool SkipComments = true) { @@ -136,6 +143,21 @@ static ClosureExpr *findTrailingClosureFromArgument(Expr *arg) { return nullptr; } +static size_t calcVisibleWhitespacePrefix(StringRef Line, + CodeFormatOptions Options) { + size_t Indent = 0; + for (auto Char : Line) { + if (Char == '\t') { + Indent += Options.TabWidth; + } else if (Char == ' ' || Char == '\v' || Char == '\f') { + Indent++; + } else { + break; + } + } + return Indent; +} + /// An indentation context of the target location struct IndentContext { enum ContextKind { Exact, LineStart }; @@ -258,16 +280,14 @@ class FormatContext { Optional InnermostCtx; bool InDocCommentBlock; bool InCommentLine; - bool InStringLiteral; public: FormatContext(SourceManager &SM, Optional IndentCtx, bool InDocCommentBlock = false, - bool InCommentLine = false, - bool InStringLiteral = false) + bool InCommentLine = false) :SM(SM), InnermostCtx(IndentCtx), InDocCommentBlock(InDocCommentBlock), - InCommentLine(InCommentLine), InStringLiteral(InStringLiteral) { } + InCommentLine(InCommentLine) { } bool IsInDocCommentBlock() { return InDocCommentBlock; @@ -277,10 +297,6 @@ class FormatContext { return InCommentLine; } - bool IsInStringLiteral() const { - return InStringLiteral; - } - void padToExactColumn(StringBuilder &Builder, const CodeFormatOptions &FmtOptions) { assert(isExact() && "Context is not exact?"); @@ -1208,8 +1224,9 @@ class FormatWalker : public ASTWalker { bool InDocCommentBlock = false; /// Whether the target location appears within a line comment. bool InCommentLine = false; - /// Whether the target location appears within a string literal. - bool InStringLiteral = false; + + /// The range of the string literal the target is inside of (if any, invalid otherwise). + CharSourceRange StringLiteralRange; public: explicit FormatWalker(SourceFile &SF, SourceManager &SM, CodeFormatOptions &Options) @@ -1224,7 +1241,8 @@ class FormatWalker : public ASTWalker { CtxOverride.clear(); TargetLocation = Loc; TargetLineLoc = Lexer::getLocForStartOfLine(SM, TargetLocation); - InDocCommentBlock = InCommentLine = InStringLiteral = false; + InDocCommentBlock = InCommentLine = false; + StringLiteralRange = CharSourceRange(); NodesToSkip.clear(); CurrentTokIt = TokenList.begin(); @@ -1234,14 +1252,99 @@ class FormatWalker : public ASTWalker { if (InnermostCtx) CtxOverride.applyIfNeeded(SM, *InnermostCtx); + if (StringLiteralRange.isValid()) { + assert(!InDocCommentBlock && !InCommentLine && + "Target is in both a string and comment"); + InnermostCtx = indentWithinStringLiteral(); + } else { + assert(!InDocCommentBlock || !InCommentLine && + "Target is in both a doc comment block and comment line"); + } + return FormatContext(SM, InnermostCtx, InDocCommentBlock, - InCommentLine, InStringLiteral); + InCommentLine); } +private: + + Optional indentWithinStringLiteral() { + assert(StringLiteralRange.isValid() && "Target is not within a string literal"); + + // This isn't ideal since if the user types """""" and then an enter + // inside after, we won't indent the end quotes. But indenting the end + // quotes could lead to an error in the rest of the string, so best to + // avoid it entirely for now. + if (isOnSameLine(SM, TargetLineLoc, StringLiteralRange.getEnd())) + return IndentContext {TargetLocation, false, IndentContext::Exact}; + + // If there's contents before the end quotes then it's likely the quotes + // are actually the start quotes of the next string in the file. Pretend + // they don't exist so their indent doesn't affect the indenting. + SourceLoc EndLineContentLoc = + getLocForContentStartOnSameLine(SM, StringLiteralRange.getEnd()); + bool HaveEndQuotes = CharSourceRange(SM, EndLineContentLoc, + StringLiteralRange.getEnd()) + .str().equals(StringRef("\"\"\"")); + + if (!HaveEndQuotes) { + // Indent to the same indentation level as the first non-empty line + // before the target. If that line is the start line then either use + // the same indentation of the start quotes if they are on their own + // line, or an extra indentation otherwise. + // + // This will indent lines with content on it as well, which should be + // fine since it is quite unlikely anyone would format a range that + // includes an unterminated string. + + SourceLoc AlignLoc = TargetLineLoc; + while (SM.isBeforeInBuffer(StringLiteralRange.getStart(), AlignLoc)) { + AlignLoc = Lexer::getLocForStartOfLine(SM, AlignLoc.getAdvancedLoc(-1)); + if (!isLineAtLocEmpty(SM, AlignLoc)) { + AlignLoc = getLocForContentStartOnSameLine(SM, AlignLoc); + break; + } + } + + if (isOnSameLine(SM, AlignLoc, StringLiteralRange.getStart())) { + SourceLoc StartLineContentLoc = + getLocForContentStartOnSameLine(SM, StringLiteralRange.getStart()); + bool StartLineOnlyQuotes = CharSourceRange(SM, StartLineContentLoc, + StringLiteralRange.getEnd()) + .str().startswith(StringRef("\"\"\"")); + if (!StartLineOnlyQuotes) + return IndentContext {StringLiteralRange.getStart(), true}; + + AlignLoc = StringLiteralRange.getStart(); + } + + return IndentContext {AlignLoc, false, IndentContext::Exact}; + } + + // If there are end quotes, only enforce a minimum indentation. We don't + // want to add any other indentation since that could add unintended + // whitespace to existing strings. Could change this if the full range + // was passed rather than a single line - in that case we *would* indent + // if the range was a single empty line. + + CharSourceRange TargetIndentRange = + CharSourceRange(SM, Lexer::getLocForStartOfLine(SM, TargetLocation), + TargetLocation); + CharSourceRange EndIndentRange = + CharSourceRange(SM, Lexer::getLocForStartOfLine(SM, EndLineContentLoc), + EndLineContentLoc); + + size_t TargetIndent = + calcVisibleWhitespacePrefix(TargetIndentRange.str(), FmtOptions); + size_t EndIndent = + calcVisibleWhitespacePrefix(EndIndentRange.str(), FmtOptions); + if (TargetIndent >= EndIndent) + return IndentContext {TargetLocation, false, IndentContext::Exact}; + + return IndentContext {EndLineContentLoc, false, IndentContext::Exact}; + } #pragma mark ASTWalker overrides and helpers -private: bool walkCustomAttributes(Decl *D) { // CustomAttrs of non-param VarDecls are handled when this method is called // on their containing PatternBindingDecls (below). @@ -1330,7 +1433,7 @@ class FormatWalker : public ASTWalker { SM.isBeforeInBuffer(E->getStartLoc(), TargetLocation) && SM.isBeforeInBuffer(TargetLocation, Lexer::getLocForEndOfToken(SM, E->getEndLoc()))) { - InStringLiteral = true; + StringLiteralRange = Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); } // Create a default indent context for all top-level expressions @@ -1352,7 +1455,7 @@ class FormatWalker : public ASTWalker { // Don't visit the child expressions of interpolated strings directly - // visit only the argument of each appendInterpolation call instead, and - // update InStringLiteral for each segment. + // set StringLiteralRange if needed for each segment. if (auto *ISL = dyn_cast(E)) { if (Action.shouldVisitChildren()) { llvm::SaveAndRestore(Parent, ISL); @@ -1364,7 +1467,8 @@ class FormatWalker : public ASTWalker { // Handle the preceeding string segment. CharSourceRange StringRange(SM, PrevStringStart, CE->getStartLoc()); if (StringRange.contains(TargetLocation)) { - InStringLiteral = true; + StringLiteralRange = + Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); return; } // Walk into the interpolation segment. @@ -1378,7 +1482,8 @@ class FormatWalker : public ASTWalker { SourceLoc End = Lexer::getLocForEndOfToken(SM, ISL->getStartLoc()); CharSourceRange StringRange(SM, PrevStringStart, End); if (StringRange.contains(TargetLocation)) - InStringLiteral = true; + StringLiteralRange = + Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()); return {false, E}; } @@ -1467,7 +1572,7 @@ class FormatWalker : public ASTWalker { } void scanTokensUntil(SourceLoc Loc) { - if (InDocCommentBlock || InCommentLine) + if (InDocCommentBlock || InCommentLine || StringLiteralRange.isValid()) return; for (auto Invalid = Loc.isInvalid(); CurrentTokIt != TokenList.end() && (Invalid || SM.isBeforeInBuffer(CurrentTokIt->getLoc(), Loc)); @@ -1477,16 +1582,16 @@ class FormatWalker : public ASTWalker { SourceLoc StartLineLoc = Lexer::getLocForStartOfLine( SM, CommentRange.getStart()); - // The -1 is needed in case the past-the-end position is a newline - // character. In that case getLocForStartOfLine returns the start of - // the next line. SourceLoc EndLineLoc = Lexer::getLocForStartOfLine( - SM, CommentRange.getEnd().getAdvancedLoc(-1)); + SM, CommentRange.getEnd()); auto TokenStr = CurrentTokIt->getRange().str(); InDocCommentBlock |= SM.isBeforeInBuffer(StartLineLoc, TargetLineLoc) && !SM.isBeforeInBuffer(EndLineLoc, TargetLineLoc) && TokenStr.startswith("/*"); InCommentLine |= StartLineLoc == TargetLineLoc && TokenStr.startswith("//"); + } else if (CurrentTokIt->getKind() == tok::unknown && + CurrentTokIt->getRange().str().startswith("\"\"\"")) { + StringLiteralRange = CurrentTokIt->getRange(); } } } @@ -2797,12 +2902,6 @@ class CodeFormatter { std::pair indent(unsigned LineIndex, FormatContext &FC, StringRef Text) { - if (FC.IsInStringLiteral()) { - return std::make_pair( - LineRange(LineIndex, 1), - swift::ide::getTextForLine(LineIndex, Text, /*Trim*/ false).str()); - } - if (FC.isExact()) { StringRef Line = swift::ide::getTextForLine(LineIndex, Text, /*Trim*/true); StringBuilder Builder; diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-interp.swift b/test/SourceKit/CodeFormat/indent-multiline-string-interp.swift new file mode 100644 index 0000000000000..e88853322c7cb --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-interp.swift @@ -0,0 +1,57 @@ +let s1 = """ + \( + 45 +) + """ + +let s2 = """ + \( + 45 + ) +""" + +let s3 = """ +\( + 45 +) + """ + +let s4 = """ + foo \( 45 /* +comment content +*/) bar + """ + +// RUN: %sourcekitd-test -req=format -line=2 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=3 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=4 %s >>%t.response + +// RUN: %sourcekitd-test -req=format -line=8 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=9 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=10 %s >>%t.response + +// RUN: %sourcekitd-test -req=format -line=14 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=15 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=16 %s >>%t.response + +// RUN: %sourcekitd-test -req=format -line=20 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=21 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=22 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " \\(" +// CHECK: key.sourcetext: " 45" +// CHECK: key.sourcetext: " )" + +// CHECK: key.sourcetext: " \\(" +// CHECK: key.sourcetext: " 45" +// CHECK: key.sourcetext: " )" + +// CHECK: key.sourcetext: " \\(" +// CHECK: key.sourcetext: " 45" +// CHECK: key.sourcetext: ")" + +// CHECK: key.sourcetext: " foo \\( 45 /*" +// CHECK: key.sourcetext: " comment content" +// CHECK: key.sourcetext: " */) bar" diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-nested.swift b/test/SourceKit/CodeFormat/indent-multiline-string-nested.swift new file mode 100644 index 0000000000000..feeff5ef5c468 --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-nested.swift @@ -0,0 +1,25 @@ +func foo() { + let s1 = """ + this is line1 in outer string \(""" + nested string in interpolation + """) + + this is line2 in outer string + """ +} + +// RUN: %sourcekitd-test -req=format -line=3 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=4 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=5 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=6 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=7 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=8 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " this is line1 in outer string \\(\"\"\"" +// CHECK: key.sourcetext: " nested string in interpolation" +// CHECK: key.sourcetext: " \"\"\")" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line2 in outer string" +// CHECK: key.sourcetext: " \"\"\"" diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-trailing-interp.swift b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-interp.swift new file mode 100644 index 0000000000000..254f91c087f40 --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-interp.swift @@ -0,0 +1,31 @@ +// RUN: %sourcekitd-test -req=format -line=24 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=25 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=26 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=27 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=28 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=29 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=30 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=31 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// The end quotes are ignored as it would be impossible to know whether +// they are part of the interpolation or another string, etc. +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: "" +// CHECK: key.sourcetext: "this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " and this is a line with trailing interpolation \\(1 +" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " \"\"\"" + +let s1 = """ + +this is line1 + + this is line2 + + and this is a line with trailing interpolation \(1 + + + """ diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-trailing-ownline.swift b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-ownline.swift new file mode 100644 index 0000000000000..a709366985b4d --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-trailing-ownline.swift @@ -0,0 +1,24 @@ +// RUN: %sourcekitd-test -req=format -line=19 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=20 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=21 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=22 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=23 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=24 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: "" +// CHECK: key.sourcetext: "this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " " + +let s1 = + """ + +this is line1 + + this is line2 + + diff --git a/test/SourceKit/CodeFormat/indent-multiline-string-trailing.swift b/test/SourceKit/CodeFormat/indent-multiline-string-trailing.swift new file mode 100644 index 0000000000000..aad9b33e03312 --- /dev/null +++ b/test/SourceKit/CodeFormat/indent-multiline-string-trailing.swift @@ -0,0 +1,23 @@ +// RUN: %sourcekitd-test -req=format -line=18 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=19 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=20 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=21 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=22 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=23 %s >>%t.response + +// RUN: %FileCheck --strict-whitespace %s <%t.response + +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: "" +// CHECK: key.sourcetext: "this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " " + +let s1 = """ + +this is line1 + + this is line2 + + diff --git a/test/SourceKit/CodeFormat/indent-multiline-string.swift b/test/SourceKit/CodeFormat/indent-multiline-string.swift index bab0eb7c80f32..3348f32c5eeab 100644 --- a/test/SourceKit/CodeFormat/indent-multiline-string.swift +++ b/test/SourceKit/CodeFormat/indent-multiline-string.swift @@ -1,20 +1,44 @@ func foo() { let s1 = """ -this is line1, - this is line2, + +this is line1 + + this is line2 + + + this is line3 + this is a line with interpolation \(1 + + 2) + """ + + let s2 = """ """ - let s1 = - "content" } -// RUN: %sourcekitd-test -req=format -line=3 -length=1 %s >%t.response -// RUN: %sourcekitd-test -req=format -line=4 -length=1 %s >>%t.response -// RUN: %sourcekitd-test -req=format -line=5 -length=1 %s >>%t.response -// RUN: %sourcekitd-test -req=format -line=7 -length=1 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=2 %s >%t.response +// RUN: %sourcekitd-test -req=format -line=3 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=4 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=5 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=6 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=7 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=8 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=9 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=10 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=11 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=12 %s >>%t.response +// RUN: %sourcekitd-test -req=format -line=15 %s >>%t.response // RUN: %FileCheck --strict-whitespace %s <%t.response -// CHECK: key.sourcetext: "this is line1," -// CHECK: key.sourcetext: " this is line2," +// CHECK: key.sourcetext: " let s1 = \"\"\"" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line1" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line2" +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " " +// CHECK: key.sourcetext: " this is line3" +// CHECK: key.sourcetext: " this is a line with interpolation \\(1 +" +// CHECK: key.sourcetext: " 2)" +// CHECK: key.sourcetext: " \"\"\"" // CHECK: key.sourcetext: "\"\"\"" -// CHECK: key.sourcetext: " \"content\"" From 92bc89b78f1743c431b89a8989a8c63e6496cad0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 12 Aug 2020 16:28:22 -0400 Subject: [PATCH 109/663] GSB: Add an inferred AnyObject constraint to @objc protocol requirement signatures This simplifies GenericSignatureImpl::requiresClass(), which no longer has to look through the conformances of the equivalence class. --- lib/AST/ASTPrinter.cpp | 13 +++++++++++-- lib/AST/GenericSignature.cpp | 10 ---------- lib/AST/GenericSignatureBuilder.cpp | 16 ++++++++++++++-- lib/SIL/IR/SILFunctionType.cpp | 9 +-------- lib/Serialization/ModuleFormat.h | 2 +- test/api-digester/Outputs/clang-module-dump.txt | 2 ++ 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 49305518234fc..72fabc46d94a5 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -1297,9 +1297,9 @@ bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) { bool inWhereClause; switch (req.getKind()) { + case RequirementKind::Layout: case RequirementKind::Conformance: - case RequirementKind::Superclass: - case RequirementKind::Layout: { + case RequirementKind::Superclass: { auto subject = req.getFirstType(); auto result = findRelevantDeclAndDirectUse(subject); @@ -1351,6 +1351,15 @@ void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto, proto->getRequirementSignature()), PrintInherited, [&](const Requirement &req) { + // Skip the inferred 'Self : AnyObject' constraint if this is an + // @objc protocol. + if (req.getKind() == RequirementKind::Layout && + req.getFirstType()->isEqual(proto->getProtocolSelfType()) && + req.getLayoutConstraint()->getKind() == LayoutConstraintKind::Class && + proto->isObjC()) { + return false; + } + auto location = bestRequirementPrintLocation(proto, req); return location.AttachedTo == attachingTo && !location.InWhereClause; }); diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 9b6befde6a9ea..ddb527c8134ec 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -404,16 +404,6 @@ bool GenericSignatureImpl::requiresClass(Type type) const { // If there is a layout constraint, it might be a class. if (equivClass->layout && equivClass->layout->isClass()) return true; - // If there is a superclass bound, then obviously it must be a class. - // FIXME: We shouldn't need this? - if (equivClass->superclass) return true; - - // If any of the protocols are class-bound, then it must be a class. - // FIXME: We shouldn't need this? - for (const auto &conforms : equivClass->conformsTo) { - if (conforms.first->requiresClass()) return true; - } - return false; } diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index dc03dc5cc0c61..b4c97fa21fd1c 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -3871,9 +3871,21 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement( return false; }); - // Remaining logic is not relevant in ObjC protocol cases. - if (proto->isObjC()) + if (proto->isObjC()) { + // @objc implies an inferred AnyObject constraint. + auto innerSource = + FloatingRequirementSource::viaProtocolRequirement(source, proto, + /*inferred=*/true); + addLayoutRequirementDirect(selfType, + LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Class, + getASTContext()), + innerSource); + return ConstraintResult::Resolved; + } + + // Remaining logic is not relevant in ObjC protocol cases. // Collect all of the inherited associated types and typealiases in the // inherited protocols (recursively). diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 5fe7a5d592ae3..bcd637442b5a1 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -1214,8 +1214,6 @@ class SubstFunctionTypeCollector { substRequirements.push_back( Requirement(RequirementKind::Layout, param, layout)); } - } else { - (void)0; } for (unsigned i : indices(upperBoundConformances)) { @@ -1313,12 +1311,7 @@ class SubstFunctionTypeCollector { CanType binding, ArchetypeType *upperBound, ArrayRef bindingConformances) -> CanType { - // TODO: ArchetypeType::getLayoutConstraint sometimes misses out on - // implied layout constraints. For now AnyObject is the only one we - // care about. - return addSubstitution(archetype->requiresClass() - ? LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class) - : LayoutConstraint(), + return addSubstitution(archetype->getLayoutConstraint(), binding, upperBound, bindingConformances); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 6c2cf423887f7..0958cb9c56671 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 569; // subclass scope +const uint16_t SWIFTMODULE_VERSION_MINOR = 570; // @objc protocols get AnyObject constraint /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/test/api-digester/Outputs/clang-module-dump.txt b/test/api-digester/Outputs/clang-module-dump.txt index 43ec745788e68..3f928e1abbc71 100644 --- a/test/api-digester/Outputs/clang-module-dump.txt +++ b/test/api-digester/Outputs/clang-module-dump.txt @@ -43,6 +43,7 @@ "declKind": "Protocol", "usr": "c:objc(pl)AnotherObjcProt", "moduleName": "Foo", + "genericSig": "", "objc_name": "AnotherObjcProt", "declAttributes": [ "ObjC", @@ -196,6 +197,7 @@ "declKind": "Protocol", "usr": "c:objc(pl)ObjcProt", "moduleName": "Foo", + "genericSig": "", "objc_name": "ObjcProt", "declAttributes": [ "ObjC", From c123f4206f2fda4d5e75d3c6eaec03ccad7df62f Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 12 Aug 2020 22:05:29 -0700 Subject: [PATCH 110/663] [Build System] Move host lipo step after install step --- utils/build-script | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/build-script b/utils/build-script index 15a84b54ada09..44819a859feac 100755 --- a/utils/build-script +++ b/utils/build-script @@ -996,6 +996,9 @@ class BuildScriptInvocation(object): for host_target in all_hosts: for product_class in impl_product_classes: self._execute_install_action(host_target, product_class) + + # Lipo... + self._execute_merged_host_lipo_action() # Non-build-script-impl products... # Note: currently only supports building for the host. @@ -1036,9 +1039,6 @@ class BuildScriptInvocation(object): for host_target in all_hosts: self._execute_package_action(host_target) - # Lipo... - self._execute_merged_host_lipo_action() - def _execute_build_action(self, host_target, product_class): action_name = "{}-{}-build".format(host_target.name, product_class.product_name()) From a535463062d64e811f69ad13466877984e856f65 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 12 Aug 2020 22:15:15 -0700 Subject: [PATCH 111/663] [Concurrency] async autoclosures are only legal on async functions. --- include/swift/AST/DiagnosticsSema.def | 32 ++++++++++++++++----------- lib/Sema/TypeCheckDecl.cpp | 14 +++++++++++- test/expr/unary/async_await.swift | 18 ++++++++------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ba013ef17706c..e6256296a359f 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2174,9 +2174,6 @@ NOTE(protocol_witness_settable_conflict,none, "candidate is not settable, but protocol requires it", ()) NOTE(protocol_witness_rethrows_conflict,none, "candidate is not 'rethrows', but protocol requires it", ()) -NOTE(protocol_witness_async_conflict,none, - "candidate is %select{not |}0'async', but protocol requirement is%select{| not}0", - (bool)) NOTE(protocol_witness_throws_conflict,none, "candidate throws, but protocol does not allow it", ()) NOTE(protocol_witness_not_objc,none, @@ -4036,6 +4033,16 @@ NOTE(note_error_to_optional,none, "did you mean to handle error as optional value?", ()) NOTE(note_disable_error_propagation,none, "did you mean to disable error propagation?", ()) + +WARNING(no_throw_in_try,none, + "no calls to throwing functions occur within 'try' expression", ()) + +WARNING(no_throw_in_do_with_catch,none, + "'catch' block is unreachable because no errors are thrown in 'do' block", ()) + +//------------------------------------------------------------------------------ +// MARK: Concurrency +//------------------------------------------------------------------------------ ERROR(async_call_without_await,none, "call is 'async' but is not marked with 'await'", ()) ERROR(async_call_without_await_in_autoclosure,none, @@ -4056,12 +4063,15 @@ ERROR(async_in_nonasync_function,none, (bool, bool)) NOTE(note_add_async_to_function,none, "add 'async' to function %0 to make it asynchronous", (DeclName)) - -WARNING(no_throw_in_try,none, - "no calls to throwing functions occur within 'try' expression", ()) - -WARNING(no_throw_in_do_with_catch,none, - "'catch' block is unreachable because no errors are thrown in 'do' block", ()) +ERROR(not_objc_function_async,none, + "'async' function cannot be represented in Objective-C", ()) +NOTE(not_objc_function_type_async,none, + "'async' function types cannot be represented in Objective-C", ()) +NOTE(protocol_witness_async_conflict,none, + "candidate is %select{not |}0'async', but protocol requirement is%select{| not}0", + (bool)) +ERROR(async_autoclosure_nonasync_function,none, + "'async' autoclosure parameter in a non-'async' function", ()) //------------------------------------------------------------------------------ // MARK: Type Check Types @@ -4417,10 +4427,6 @@ NOTE(not_objc_generic_type_param,none, NOTE(not_objc_function_type_param,none, "function types cannot be represented in Objective-C unless their " "parameters and returns can be", ()) -ERROR(not_objc_function_async,none, - "'async' function cannot be represented in Objective-C", ()) -NOTE(not_objc_function_type_async,none, - "'async' function types cannot be represented in Objective-C", ()) NOTE(not_objc_function_type_throwing,none, "throwing function types cannot be represented in Objective-C", ()) NOTE(objc_inferring_on_objc_protocol_member,none, diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index c364de02f8eb0..455666f79e51e 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2148,9 +2148,21 @@ static Type validateParameterType(ParamDecl *decl) { decl->setInvalid(); return ErrorType::get(ctx); } + } - return Ty; + // async autoclosures can only occur as parameters to async functions. + if (decl->isAutoClosure()) { + if (auto fnType = Ty->getAs()) { + if (fnType->isAsync() && + !(isa(dc) && + cast(dc)->hasAsync())) { + auto func = cast(dc); + decl->diagnose(diag::async_autoclosure_nonasync_function); + func->diagnose(diag::note_add_async_to_function, func->getName()); + } + } } + return Ty; } diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index c7c7c89894766..0634d0d0574b0 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -33,20 +33,22 @@ struct SomeStruct { static var y = __await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}} } -func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) { } -func acceptAutoclosureAsync(_: @autoclosure () async -> Int) { } +func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { } +func acceptAutoclosureAsync(_: @autoclosure () async -> Int) async { } + +func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) { } +// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}} +// expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}} func testAutoclosure() async { - acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} - acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + __await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} + __await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} - acceptAutoclosureAsync(__await getInt()) - acceptAutoclosureNonAsync(__await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + __await acceptAutoclosureAsync(__await getInt()) + __await acceptAutoclosureNonAsync(__await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} __await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} - // expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}} __await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} - // expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}} } // Test inference of 'async' from the body of a closure. From eda621fb645b2eb443d8febe3c76dbbd92490eab Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 12 Aug 2020 22:17:29 -0700 Subject: [PATCH 112/663] [Concurrency] Only suggest adding 'async' to functions. --- lib/Sema/TypeCheckDecl.cpp | 5 +++-- test/expr/unary/async_await.swift | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 455666f79e51e..cf6c3e3864d99 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2156,9 +2156,10 @@ static Type validateParameterType(ParamDecl *decl) { if (fnType->isAsync() && !(isa(dc) && cast(dc)->hasAsync())) { - auto func = cast(dc); decl->diagnose(diag::async_autoclosure_nonasync_function); - func->diagnose(diag::note_add_async_to_function, func->getName()); + if (auto func = dyn_cast(dc)) { + func->diagnose(diag::note_add_async_to_function, func->getName()); + } } } } diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index 0634d0d0574b0..68f006a0ab537 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -40,6 +40,11 @@ func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) { } // expected-error@-1{{'async' autoclosure parameter in a non-'async' function}} // expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}} +struct HasAsyncBad { + init(_: @autoclosure () async -> Int) { } + // expected-error@-1{{'async' autoclosure parameter in a non-'async' function}} +} + func testAutoclosure() async { __await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} __await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} From d2e162676d9a69f4a175b09bee46e3450e5c86b8 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 12 Aug 2020 18:32:48 -0300 Subject: [PATCH 113/663] Fix reading elf section from file buffer --- include/swift/Reflection/ReflectionContext.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index c3818f477eaf6..0ff6c8b44436f 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -479,12 +479,12 @@ class ReflectionContext for (const typename T::Section *Hdr : SecHdrVec) { uint32_t Offset = Hdr->sh_name; const char *Start = (const char *)StrTab + Offset; - uint64_t Size = strnlen(Start, StrTabSize - Offset); - if (Size > StrTabSize - Offset) { + uint64_t StringSize = strnlen(Start, StrTabSize - Offset); + if (StringSize > StrTabSize - Offset) { Error = true; break; } - std::string SecName(Start, Size); + std::string SecName(Start, StringSize); if (SecName != Name) continue; RemoteAddress SecStart = @@ -495,7 +495,7 @@ class ReflectionContext // sh_offset gives us the offset to the section in the file, // while sh_addr gives us the offset in the process. auto Offset = Hdr->sh_offset; - if (FileBuffer->allocatedSize() > Offset + Size) { + if (FileBuffer->allocatedSize() < Offset + SecSize) { Error = true; break; } @@ -503,7 +503,8 @@ class ReflectionContext SecBuf = MemoryReader::ReadBytesResult( Buf, [](const void *ptr) { free(const_cast(ptr)); }); memcpy((void *)Buf, - (const void *)((uint64_t)FileBuffer->base() + Offset), Size); + (const void *)((uint64_t)FileBuffer->base() + Offset), + SecSize); } else { SecBuf = this->getReader().readBytes(SecStart, SecSize); } From b070e851f81045d9c3c2602b7bc86f09ec99ed89 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 13 Aug 2020 08:55:04 -0700 Subject: [PATCH 114/663] [ASTScope] Simplify binary search code in findChildContaining() The comparision happens only by 'comp(element, value)' not 'comp(value, element)'. We only need `operator()(const ASTScopeImpl *, SourceLoc)`. Use llvm::lower_bound() instead of std::lower_bound(). --- lib/AST/ASTScopeLookup.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index b507343592abf..250f2ad6c0678 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -30,7 +30,6 @@ #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" #include "llvm/Support/Compiler.h" -#include using namespace swift; using namespace namelookup; @@ -170,22 +169,15 @@ NullablePtr ASTScopeImpl::findChildContaining(SourceLoc loc, SourceManager &sourceMgr) const { // Use binary search to find the child that contains this location. - struct CompareLocs { - SourceManager &sourceMgr; - - bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); - auto rangeOfScope = scope->getSourceRangeOfScope(); - loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); - return -1 == ASTScopeImpl::compare(rangeOfScope, loc, sourceMgr, - /*ensureDisjoint=*/false); - } - bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { - return !(*this)(scope, loc); - } - }; - auto *const *child = std::lower_bound( - getChildren().begin(), getChildren().end(), loc, CompareLocs{sourceMgr}); + auto *const *child = llvm::lower_bound( + getChildren(), loc, + [&sourceMgr](const ASTScopeImpl *scope, SourceLoc loc) { + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); + auto rangeOfScope = scope->getSourceRangeOfScope(); + loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); + return -1 == ASTScopeImpl::compare(rangeOfScope, loc, sourceMgr, + /*ensureDisjoint=*/false); + }); if (child != getChildren().end()) { auto rangeOfScope = (*child)->getSourceRangeOfScope(); From f6976d862022fd3c79b2ba65b512ddf2555ccec8 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 13 Aug 2020 10:21:37 -0700 Subject: [PATCH 115/663] Have TBDGenDescriptor take ownership of TBDGenOptions This is necessary for caching TBD requests. --- include/swift/AST/TBDGenRequests.h | 5 +++-- include/swift/TBDGen/TBDGen.h | 2 +- lib/FrontendTool/FrontendTool.cpp | 1 + lib/FrontendTool/TBD.cpp | 1 + lib/IRGen/IRGenRequests.cpp | 2 +- lib/TBDGen/TBDGen.cpp | 2 +- lib/TBDGen/TBDGenVisitor.h | 2 +- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/swift/AST/TBDGenRequests.h b/include/swift/AST/TBDGenRequests.h index 66ac0ef814e04..cd52948b73693 100644 --- a/include/swift/AST/TBDGenRequests.h +++ b/include/swift/AST/TBDGenRequests.h @@ -19,6 +19,7 @@ #include "swift/AST/ASTTypeIDs.h" #include "swift/AST/SimpleRequest.h" +#include "swift/TBDGen/TBDGen.h" namespace llvm { @@ -37,12 +38,11 @@ namespace swift { class FileUnit; class ModuleDecl; -struct TBDGenOptions; class TBDGenDescriptor final { using FileOrModule = llvm::PointerUnion; FileOrModule Input; - const TBDGenOptions &Opts; + TBDGenOptions Opts; TBDGenDescriptor(FileOrModule input, const TBDGenOptions &opts) : Input(input), Opts(opts) { @@ -62,6 +62,7 @@ class TBDGenDescriptor final { /// Returns the TBDGen options. const TBDGenOptions &getOptions() const { return Opts; } + TBDGenOptions &getOptions() { return Opts; } const llvm::DataLayout &getDataLayout() const; const llvm::Triple &getTarget() const; diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 72229a63707cc..a200aae1d10f3 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -14,7 +14,6 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringSet.h" -#include "swift/AST/TBDGenRequests.h" #include "swift/Basic/Version.h" #include @@ -25,6 +24,7 @@ class raw_ostream; namespace swift { class FileUnit; class ModuleDecl; +class TBDGenDescriptor; /// Options for controlling the exact set of symbols included in the TBD /// output. diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 567c95b45319b..3dfa4312e7574 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -35,6 +35,7 @@ #include "swift/AST/IRGenRequests.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/TBDGenRequests.h" #include "swift/AST/TypeRefinementContext.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/Edit.h" diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp index 77a27a2152e87..f64d86ee13c38 100644 --- a/lib/FrontendTool/TBD.cpp +++ b/lib/FrontendTool/TBD.cpp @@ -17,6 +17,7 @@ #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" +#include "swift/AST/TBDGenRequests.h" #include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangle.h" #include "swift/Frontend/FrontendOptions.h" diff --git a/lib/IRGen/IRGenRequests.cpp b/lib/IRGen/IRGenRequests.cpp index 7cff6f7782837..85f9daae3058a 100644 --- a/lib/IRGen/IRGenRequests.cpp +++ b/lib/IRGen/IRGenRequests.cpp @@ -16,8 +16,8 @@ #include "swift/AST/Module.h" #include "swift/AST/SourceFile.h" #include "swift/SIL/SILModule.h" +#include "swift/AST/TBDGenRequests.h" #include "swift/Subsystems.h" -#include "swift/TBDGen/TBDGen.h" #include "llvm/IR/Module.h" #include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index bb90f41674faa..39719dec2a0e0 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -61,7 +61,7 @@ static bool isGlobalOrStaticVar(VarDecl *VD) { return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); } -TBDGenVisitor::TBDGenVisitor(TBDGenDescriptor desc, +TBDGenVisitor::TBDGenVisitor(const TBDGenDescriptor &desc, SymbolCallbackFn symbolCallback) : TBDGenVisitor(desc.getTarget(), desc.getDataLayout(), desc.getParentModule(), desc.getOptions(), diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 0f14e71476568..681325fc3e21e 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -150,7 +150,7 @@ class TBDGenVisitor : public ASTVisitor { /// Create a new visitor using the target and layout information from a /// TBDGenDescriptor. - TBDGenVisitor(TBDGenDescriptor desc, SymbolCallbackFn symbolCallback); + TBDGenVisitor(const TBDGenDescriptor &desc, SymbolCallbackFn symbolCallback); ~TBDGenVisitor() { assert(DeclStack.empty()); } void addMainIfNecessary(FileUnit *file) { From 96f3b8759d02a1bcb0033886b9b84639939c041f Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 13 Aug 2020 10:21:38 -0700 Subject: [PATCH 116/663] Introduce SymbolSourceMapRequest Add a request that leverages the TBDGenVisitor to produce a mapping from a mangled symbol name to the SIL or IR entity that emits it. This will be used to enable lazy compilation where only a specific set of symbols need to be emitted. --- include/swift/AST/ASTTypeIDZone.def | 1 + include/swift/AST/ASTTypeIDs.h | 1 + include/swift/AST/TBDGenRequests.h | 119 +++++++++++++++++++++++++ include/swift/AST/TBDGenTypeIDZone.def | 3 + lib/TBDGen/TBDGen.cpp | 72 ++++++++++----- lib/TBDGen/TBDGenVisitor.h | 13 +-- 6 files changed, 182 insertions(+), 27 deletions(-) diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index bf6aeaf1e65dc..fa9dd1d3a8d3c 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -28,6 +28,7 @@ SWIFT_TYPEID(Requirement) SWIFT_TYPEID(ResilienceExpansion) SWIFT_TYPEID(FragileFunctionKind) SWIFT_TYPEID(TangentPropertyInfo) +SWIFT_TYPEID(SymbolSourceMap) SWIFT_TYPEID(Type) SWIFT_TYPEID(TypePair) SWIFT_TYPEID(TypeWitnessAndDecl) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index 973f7dc2c9836..6fc964d6fa305 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -60,6 +60,7 @@ class Requirement; enum class ResilienceExpansion : unsigned; struct FragileFunctionKind; class SourceFile; +class SymbolSourceMap; struct TangentPropertyInfo; class Type; class TypeAliasDecl; diff --git a/include/swift/AST/TBDGenRequests.h b/include/swift/AST/TBDGenRequests.h index cd52948b73693..413f79b326568 100644 --- a/include/swift/AST/TBDGenRequests.h +++ b/include/swift/AST/TBDGenRequests.h @@ -19,6 +19,8 @@ #include "swift/AST/ASTTypeIDs.h" #include "swift/AST/SimpleRequest.h" +#include "swift/IRGen/Linking.h" +#include "swift/SIL/SILDeclRef.h" #include "swift/TBDGen/TBDGen.h" namespace llvm { @@ -118,6 +120,123 @@ class PublicSymbolsRequest evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const; }; +/// Describes the origin of a particular symbol, including the stage of +/// compilation it is introduced, as well as information on what decl introduces +/// it. +class SymbolSource { +public: + enum class Kind { + /// A symbol introduced when emitting a SIL decl. + SIL, + + /// A symbol introduced when emitting LLVM IR. + IR, + + /// A symbol used to customize linker behavior, introduced by TBDGen. + LinkerDirective, + + /// A symbol with an unknown origin. + // FIXME: This should be eliminated. + Unknown + }; + Kind kind; + +private: + union { + SILDeclRef silDeclRef; + irgen::LinkEntity irEntity; + }; + + explicit SymbolSource(SILDeclRef ref) : kind(Kind::SIL) { + silDeclRef = ref; + } + explicit SymbolSource(irgen::LinkEntity entity) : kind(Kind::IR) { + irEntity = entity; + } + explicit SymbolSource(Kind kind) : kind(kind) { + assert(kind == Kind::LinkerDirective || kind == Kind::Unknown); + } + +public: + static SymbolSource forSILDeclRef(SILDeclRef ref) { + return SymbolSource{ref}; + } + static SymbolSource forIRLinkEntity(irgen::LinkEntity entity) { + return SymbolSource{entity}; + } + static SymbolSource forLinkerDirective() { + return SymbolSource{Kind::LinkerDirective}; + } + static SymbolSource forUnknown() { + return SymbolSource{Kind::Unknown}; + } + + bool isLinkerDirective() const { + return kind == Kind::LinkerDirective; + } + + SILDeclRef getSILDeclRef() const { + assert(kind == Kind::SIL); + return silDeclRef; + } + irgen::LinkEntity getIRLinkEntity() const { + assert(kind == Kind::IR); + return irEntity; + } +}; + +/// Maps a symbol back to its source for lazy compilation. +class SymbolSourceMap { + friend class SymbolSourceMapRequest; + + using Storage = llvm::StringMap; + const Storage *storage; + + explicit SymbolSourceMap(const Storage *storage) : storage(storage) { + assert(storage); + } + +public: + Optional find(StringRef symbol) const { + auto result = storage->find(symbol); + if (result == storage->end()) + return None; + return result->second; + } + + friend bool operator==(const SymbolSourceMap &lhs, + const SymbolSourceMap &rhs) { + return lhs.storage == rhs.storage; + } + friend bool operator!=(const SymbolSourceMap &lhs, + const SymbolSourceMap &rhs) { + return !(lhs == rhs); + } + + friend void simple_display(llvm::raw_ostream &out, const SymbolSourceMap &) { + out << "(symbol storage map)"; + } +}; + +/// Computes a map of symbols to their SymbolSource for a file or module. +class SymbolSourceMapRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + SymbolSourceMap evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const; + +public: + // Cached. + bool isCached() const { return true; } +}; + /// Report that a request of the given kind is being evaluated, so it /// can be recorded by the stats reporter. template diff --git a/include/swift/AST/TBDGenTypeIDZone.def b/include/swift/AST/TBDGenTypeIDZone.def index b175b8ac19bd3..71eb7ad25a68a 100644 --- a/include/swift/AST/TBDGenTypeIDZone.def +++ b/include/swift/AST/TBDGenTypeIDZone.def @@ -19,3 +19,6 @@ SWIFT_REQUEST(TBDGen, GenerateTBDRequest, TBDFile(TBDGenDescriptor), SWIFT_REQUEST(TBDGen, PublicSymbolsRequest, std::vector(TBDGenDescriptor), Uncached, NoLocationInfo) +SWIFT_REQUEST(TBDGen, SymbolSourceMapRequest, + SymbolSourceMap(TBDGenDescriptor), + Cached, NoLocationInfo) diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 39719dec2a0e0..90d8dd3202c9f 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -67,10 +67,9 @@ TBDGenVisitor::TBDGenVisitor(const TBDGenDescriptor &desc, desc.getParentModule(), desc.getOptions(), symbolCallback) {} -void TBDGenVisitor::addSymbolInternal(StringRef name, - llvm::MachO::SymbolKind kind, - bool isLinkerDirective) { - if (!isLinkerDirective && Opts.LinkerDirectivesOnly) +void TBDGenVisitor::addSymbolInternal(StringRef name, SymbolKind kind, + SymbolSource source) { + if (!source.isLinkerDirective() && Opts.LinkerDirectivesOnly) return; #ifndef NDEBUG @@ -81,7 +80,7 @@ void TBDGenVisitor::addSymbolInternal(StringRef name, } } #endif - SymbolCallback(name, kind); + SymbolCallback(name, kind, source); } static std::vector @@ -337,8 +336,8 @@ void TBDGenVisitor::addLinkerDirectiveSymbolsLdPrevious(StringRef name, OS << IntroVer->getMajor() << "." << getMinor(IntroVer->getMinor()) << "$"; OS << Ver.Version.getMajor() << "." << getMinor(Ver.Version.getMinor()) << "$"; OS << name << "$"; - addSymbolInternal(OS.str(), llvm::MachO::SymbolKind::GlobalSymbol, - /*LinkerDirective*/true); + addSymbolInternal(OS.str(), SymbolKind::GlobalSymbol, + SymbolSource::forLinkerDirective()); } } @@ -383,18 +382,19 @@ void TBDGenVisitor::addLinkerDirectiveSymbolsLdHide(StringRef name, llvm::SmallString<64> Buffer; llvm::raw_svector_ostream OS(Buffer); OS << "$ld$hide$os" << CurMaj << "." << CurMin << "$" << name; - addSymbolInternal(OS.str(), llvm::MachO::SymbolKind::GlobalSymbol, - /*LinkerDirective*/true); + addSymbolInternal(OS.str(), SymbolKind::GlobalSymbol, + SymbolSource::forLinkerDirective()); } } } -void TBDGenVisitor::addSymbol(StringRef name, SymbolKind kind) { +void TBDGenVisitor::addSymbol(StringRef name, SymbolSource source, + SymbolKind kind) { // The linker expects to see mangled symbol names in TBD files, so make sure // to mangle before inserting the symbol. SmallString<32> mangled; llvm::Mangler::getNameWithPrefix(mangled, name, DataLayout); - addSymbolInternal(mangled, kind); + addSymbolInternal(mangled, kind, source); if (previousInstallNameMap) { addLinkerDirectiveSymbolsLdPrevious(mangled, kind); } else { @@ -407,7 +407,7 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef) { declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); if (linkage == SILLinkage::Public) - addSymbol(declRef.mangle()); + addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); } void TBDGenVisitor::addSymbol(LinkEntity entity) { @@ -419,7 +419,7 @@ void TBDGenVisitor::addSymbol(LinkEntity entity) { linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility; if (externallyVisible) - addSymbol(linkage.getName()); + addSymbol(linkage.getName(), SymbolSource::forIRLinkEntity(entity)); } void TBDGenVisitor::addDispatchThunk(SILDeclRef declRef) { @@ -490,8 +490,10 @@ void TBDGenVisitor::addConformances(const IterableDeclContext *IDC) { (isa(rootConformance) || fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef))) { Mangle::ASTMangler Mangler; - addSymbol( - Mangler.mangleWitnessThunk(rootConformance, requirementDecl)); + + // FIXME: We should have a SILDeclRef SymbolSource for this. + addSymbol(Mangler.mangleWitnessThunk(rootConformance, requirementDecl), + SymbolSource::forUnknown()); } }; @@ -542,7 +544,7 @@ void TBDGenVisitor::addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, original->getGenericSignature(), config.derivativeGenericSignature)}; std::string linearMapName = mangler.mangleAutoDiffLinearMapHelper(declRef.mangle(), kind, silConfig); - addSymbol(linearMapName); + addSymbol(linearMapName, SymbolSource::forSILDeclRef(declRef)); } void TBDGenVisitor::addAutoDiffDerivativeFunction( @@ -587,7 +589,7 @@ void TBDGenVisitor::addDifferentiabilityWitness( Mangle::ASTMangler mangler; auto mangledName = mangler.mangleSILDifferentiabilityWitnessKey(key); - addSymbol(mangledName); + addSymbol(mangledName, SymbolSource::forSILDeclRef(declRef)); } void TBDGenVisitor::addDerivativeConfiguration(AbstractFunctionDecl *original, @@ -771,8 +773,9 @@ void TBDGenVisitor::visitVarDecl(VarDecl *VD) { isGlobalOrStaticVar(VD)) { if (getDeclLinkage(VD) == FormalLinkage::PublicUnique) { // The actual variable has a symbol. + // FIXME: We ought to have a symbol source for this. Mangle::ASTMangler mangler; - addSymbol(mangler.mangleEntity(VD)); + addSymbol(mangler.mangleEntity(VD), SymbolSource::forUnknown()); } if (VD->isLazilyInitializedGlobal()) @@ -835,8 +838,10 @@ void TBDGenVisitor::visitClassDecl(ClassDecl *CD) { addSymbol(LinkEntity::forSwiftMetaclassStub(CD)); if (addObjCClass) { + // FIXME: We ought to have a symbol source for this. SmallString<128> buffer; - addSymbol(CD->getObjCRuntimeName(buffer), SymbolKind::ObjectiveCClass); + addSymbol(CD->getObjCRuntimeName(buffer), SymbolSource::forUnknown(), + SymbolKind::ObjectiveCClass); } } @@ -1048,8 +1053,10 @@ void TBDGenVisitor::visitEnumElementDecl(EnumElementDecl *EED) { void TBDGenVisitor::addFirstFileSymbols() { if (!Opts.ModuleLinkName.empty()) { + // FIXME: We ought to have a symbol source for this. SmallString<32> buf; - addSymbol(irgen::encodeForceLoadSymbolName(buf, Opts.ModuleLinkName)); + addSymbol(irgen::encodeForceLoadSymbolName(buf, Opts.ModuleLinkName), + SymbolSource::forUnknown()); } } @@ -1196,7 +1203,7 @@ TBDFile GenerateTBDRequest::evaluate(Evaluator &evaluator, } llvm::MachO::TargetList targets{target}; - auto addSymbol = [&](StringRef symbol, SymbolKind kind) { + auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { file.addSymbol(kind, symbol, targets); }; @@ -1209,7 +1216,7 @@ std::vector PublicSymbolsRequest::evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const { std::vector symbols; - auto addSymbol = [&](StringRef symbol, SymbolKind kind) { + auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { if (kind == SymbolKind::GlobalSymbol) symbols.push_back(symbol.str()); }; @@ -1231,3 +1238,24 @@ void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os, llvm::cantFail(llvm::MachO::TextAPIWriter::writeToStream(os, file), "YAML writing should be error-free"); } + +SymbolSourceMap SymbolSourceMapRequest::evaluate(Evaluator &evaluator, + TBDGenDescriptor desc) const { + using Map = SymbolSourceMap::Storage; + Map symbolSources; + + auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { + symbolSources.insert({symbol, source}); + }; + + TBDGenVisitor visitor(desc, addSymbol); + visitor.visit(desc); + + // FIXME: Once the evaluator supports returning a reference to a cached value + // in storage, this won't be necessary. + auto &ctx = desc.getParentModule()->getASTContext(); + auto *memory = ctx.Allocate(); + *memory = std::move(symbolSources); + ctx.addCleanup([memory](){ memory->~Map(); }); + return SymbolSourceMap(memory); +} diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 681325fc3e21e..3c93e8d02db56 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -42,6 +42,7 @@ namespace swift { class TBDGenDescriptor; struct TBDGenOptions; +class SymbolSource; namespace tbdgen { @@ -72,7 +73,8 @@ class TBDGenVisitor : public ASTVisitor { const TBDGenOptions &Opts; using SymbolKind = llvm::MachO::SymbolKind; - using SymbolCallbackFn = llvm::function_ref; + using SymbolCallbackFn = + llvm::function_ref; SymbolCallbackFn SymbolCallback; @@ -90,11 +92,11 @@ class TBDGenVisitor : public ASTVisitor { std::unique_ptr> parsePreviousModuleInstallNameMap(); void addSymbolInternal(StringRef name, llvm::MachO::SymbolKind kind, - bool isLinkerDirective = false); + SymbolSource source); void addLinkerDirectiveSymbolsLdHide(StringRef name, llvm::MachO::SymbolKind kind); void addLinkerDirectiveSymbolsLdPrevious(StringRef name, llvm::MachO::SymbolKind kind); - void addSymbol(StringRef name, llvm::MachO::SymbolKind kind = - llvm::MachO::SymbolKind::GlobalSymbol); + void addSymbol(StringRef name, SymbolSource source, + SymbolKind kind = SymbolKind::GlobalSymbol); void addSymbol(SILDeclRef declRef); @@ -160,8 +162,9 @@ class TBDGenVisitor : public ASTVisitor { // // Make sure to only add the main symbol for the module that we're emitting // TBD for, and not for any statically linked libraries. + // FIXME: We should have a SymbolSource for main. if (file->hasEntryPoint() && file->getParentModule() == SwiftModule) - addSymbol("main"); + addSymbol("main", SymbolSource::forUnknown()); } /// Adds the global symbols associated with the first file. From aa868085cd86200bef8538b070fbe7bc95f0748a Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 13 Aug 2020 10:21:38 -0700 Subject: [PATCH 117/663] Allow TBDGenVisitor to visit non-public symbols Add a `PublicSymbolsOnly` option to TBDGenOptions that controls whether to include public-only symbols. This is `true` by default, but will be disabled for symbol mapping. --- include/swift/TBDGen/TBDGen.h | 9 ++++-- lib/TBDGen/TBDGen.cpp | 52 +++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index a200aae1d10f3..b3d798f2c7d38 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -38,6 +38,9 @@ struct TBDGenOptions { /// Only collect linker directive symbols. bool LinkerDirectivesOnly = false; + /// Whether to include only symbols with public linkage. + bool PublicSymbolsOnly = true; + /// The install_name to use in the TBD file. std::string InstallName; @@ -66,6 +69,7 @@ struct TBDGenOptions { return lhs.HasMultipleIGMs == rhs.HasMultipleIGMs && lhs.IsInstallAPI == rhs.IsInstallAPI && lhs.LinkerDirectivesOnly == rhs.LinkerDirectivesOnly && + lhs.PublicSymbolsOnly == rhs.PublicSymbolsOnly && lhs.InstallName == rhs.InstallName && lhs.ModuleLinkName == rhs.ModuleLinkName && lhs.CurrentVersion == rhs.CurrentVersion && @@ -82,8 +86,9 @@ struct TBDGenOptions { using namespace llvm; return hash_combine( opts.HasMultipleIGMs, opts.IsInstallAPI, opts.LinkerDirectivesOnly, - opts.InstallName, opts.ModuleLinkName, opts.CurrentVersion, - opts.CompatibilityVersion, opts.ModuleInstallNameMapPath, + opts.PublicSymbolsOnly, opts.InstallName, opts.ModuleLinkName, + opts.CurrentVersion, opts.CompatibilityVersion, + opts.ModuleInstallNameMapPath, hash_combine_range(opts.embedSymbolsFromModules.begin(), opts.embedSymbolsFromModules.end())); } diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 90d8dd3202c9f..623e3d02ffb3e 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -406,8 +406,10 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef) { auto linkage = effectiveLinkageForClassMember( declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); - if (linkage == SILLinkage::Public) - addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); + if (Opts.PublicSymbolsOnly && linkage != SILLinkage::Public) + return; + + addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); } void TBDGenVisitor::addSymbol(LinkEntity entity) { @@ -418,8 +420,10 @@ void TBDGenVisitor::addSymbol(LinkEntity entity) { llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) && linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility; - if (externallyVisible) - addSymbol(linkage.getName(), SymbolSource::forIRLinkEntity(entity)); + if (Opts.PublicSymbolsOnly && !externallyVisible) + return; + + addSymbol(linkage.getName(), SymbolSource::forIRLinkEntity(entity)); } void TBDGenVisitor::addDispatchThunk(SILDeclRef declRef) { @@ -486,15 +490,21 @@ void TBDGenVisitor::addConformances(const IterableDeclContext *IDC) { auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl, ValueDecl *witnessDecl) { auto witnessRef = SILDeclRef(witnessDecl); - if (conformanceIsFixed && - (isa(rootConformance) || - fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef))) { - Mangle::ASTMangler Mangler; - - // FIXME: We should have a SILDeclRef SymbolSource for this. - addSymbol(Mangler.mangleWitnessThunk(rootConformance, requirementDecl), - SymbolSource::forUnknown()); + if (Opts.PublicSymbolsOnly) { + if (!conformanceIsFixed) + return; + + if (!isa(rootConformance) && + !fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef)) { + return; + } } + + Mangle::ASTMangler Mangler; + + // FIXME: We should have a SILDeclRef SymbolSource for this. + addSymbol(Mangler.mangleWitnessThunk(rootConformance, requirementDecl), + SymbolSource::forUnknown()); }; rootConformance->forEachValueWitness([&](ValueDecl *valueReq, @@ -525,11 +535,11 @@ void TBDGenVisitor::addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, auto declRef = SILDeclRef(original).asForeign(requiresForeignEntryPoint(original)); - if (!declRef.isSerialized()) - return; - // Linear maps are public only when the original function is serialized. - if (!declRef.isSerialized()) + // Linear maps are public only when the original function is serialized. So + // if we're only including public symbols and it's not serialized, bail. + if (Opts.PublicSymbolsOnly && !declRef.isSerialized()) return; + // Differential functions are emitted only when forward-mode is enabled. if (kind == AutoDiffLinearMapKind::Differential && !ctx.LangOpts.EnableExperimentalForwardModeDifferentiation) @@ -573,7 +583,7 @@ void TBDGenVisitor::addDifferentiabilityWitness( auto originalLinkage = declRef.getLinkage(ForDefinition); if (foreign) originalLinkage = stripExternalFromLinkage(originalLinkage); - if (originalLinkage != SILLinkage::Public) + if (Opts.PublicSymbolsOnly && originalLinkage != SILLinkage::Public) return; auto *silParamIndices = autodiff::getLoweredParameterIndices( @@ -631,7 +641,7 @@ static bool shouldUseAllocatorMangling(const AbstractFunctionDecl *afd) { void TBDGenVisitor::visitDefaultArguments(ValueDecl *VD, ParameterList *PL) { auto publicDefaultArgGenerators = SwiftModule->isTestingEnabled() || SwiftModule->arePrivateImportsEnabled(); - if (!publicDefaultArgGenerators) + if (Opts.PublicSymbolsOnly && !publicDefaultArgGenerators) return; // In Swift 3 (or under -enable-testing), default arguments (of public @@ -771,7 +781,8 @@ void TBDGenVisitor::visitVarDecl(VarDecl *VD) { // statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { - if (getDeclLinkage(VD) == FormalLinkage::PublicUnique) { + if (!Opts.PublicSymbolsOnly || + getDeclLinkage(VD) == FormalLinkage::PublicUnique) { // The actual variable has a symbol. // FIXME: We ought to have a symbol source for this. Mangle::ASTMangler mangler; @@ -814,7 +825,8 @@ void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) { } void TBDGenVisitor::visitClassDecl(ClassDecl *CD) { - if (getDeclLinkage(CD) != FormalLinkage::PublicUnique) + if (Opts.PublicSymbolsOnly && + getDeclLinkage(CD) != FormalLinkage::PublicUnique) return; auto &ctxt = CD->getASTContext(); From dd075c64c9f370c4c6bba32e9d32acbc74f65c83 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 13 Aug 2020 10:17:07 -0700 Subject: [PATCH 118/663] [Concurrency] Treat 'await' as a contextual keyword. Replace the uglified '__await' keyword with a contextual keyword 'await'. This is more of what we would actually want for the concurrency model. When concurrency is enabled, this will be a source-breaking change, because this is valid Swift code today: ```swift struct MyFuture { func await() -> } func doSomething() { let result = await() } } ``` but the call to `await()` will be parsed as an await expression when concurrency is enabled. The source break is behind the experimental concurrency flag, but this way we can see how much of an issue it is in practice. --- lib/Parse/ParseExpr.cpp | 6 ++--- test/Parse/async-syntax.swift | 6 ++++- test/Parse/async.swift | 11 ++++++++ test/expr/unary/async_await.swift | 36 +++++++++++++-------------- utils/gyb_syntax_support/ExprNodes.py | 4 ++- utils/gyb_syntax_support/Token.py | 1 - 6 files changed, 40 insertions(+), 24 deletions(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 94aef231ec5d3..1d3a63a826d11 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -379,7 +379,7 @@ ParserResult Parser::parseExprSequence(Diag<> Message, /// parseExprSequenceElement /// /// expr-sequence-element(Mode): -/// '__await' expr-sequence-element(Mode) +/// 'await' expr-sequence-element(Mode) /// 'try' expr-sequence-element(Mode) /// 'try' '?' expr-sequence-element(Mode) /// 'try' '!' expr-sequence-element(Mode) @@ -392,8 +392,8 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, SyntaxParsingContext ElementContext(SyntaxContext, SyntaxContextKind::Expr); - if (shouldParseExperimentalConcurrency() && Tok.is(tok::kw___await)) { - SourceLoc awaitLoc = consumeToken(tok::kw___await); + if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("await")) { + SourceLoc awaitLoc = consumeToken(); ParserResult sub = parseExprUnary(message, isExprBasic); if (!sub.hasCodeCompletion() && !sub.isNull()) { ElementContext.setCreateSyntax(SyntaxKind::AwaitExpr); diff --git a/test/Parse/async-syntax.swift b/test/Parse/async-syntax.swift index 4f91754b26f3f..c305fc44dd67b 100644 --- a/test/Parse/async-syntax.swift +++ b/test/Parse/async-syntax.swift @@ -12,7 +12,7 @@ func testTypeExprs() { } func testAwaitOperator() async { - let _ = __await asyncGlobal1() + let _ = await asyncGlobal1() } func testAsyncClosure() { @@ -20,3 +20,7 @@ func testAsyncClosure() { let _ = { () throws in 5 } let _ = { () async throws in 5 } } + +func testAwait() async { + let _ = await asyncGlobal1() +} diff --git a/test/Parse/async.swift b/test/Parse/async.swift index 6fee5c0bfdee6..657048a27aec6 100644 --- a/test/Parse/async.swift +++ b/test/Parse/async.swift @@ -41,3 +41,14 @@ func testTypeExprs() { let _ = [() -> async ()]() // expected-error{{'async' may only occur before '->'}}{{18-24=}}{{15-15=async }} } + +// Parsing await syntax. +struct MyFuture { + func await() -> Int { 0 } +} + +func testAwaitExpr() async { + let _ = await asyncGlobal1() + let myFuture = MyFuture() + let _ = myFuture.await() +} diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index 68f006a0ab537..71ed441070442 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -1,10 +1,10 @@ // RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency func test1(asyncfp : () async -> Int, fp : () -> Int) async { - _ = __await asyncfp() - _ = __await asyncfp() + asyncfp() - _ = __await asyncfp() + fp() - _ = __await fp() + 42 // expected-warning {{no calls to 'async' functions occur within 'await' expression}} + _ = await asyncfp() + _ = await asyncfp() + asyncfp() + _ = await asyncfp() + fp() + _ = await fp() + 42 // expected-warning {{no calls to 'async' functions occur within 'await' expression}} _ = asyncfp() // expected-error {{call is 'async' but is not marked with 'await'}} } @@ -12,25 +12,25 @@ func getInt() async -> Int { return 5 } // Locations where "await" is prohibited. func test2( - defaulted: Int = __await getInt() // expected-error{{'async' call cannot occur in a default argument}} + defaulted: Int = await getInt() // expected-error{{'async' call cannot occur in a default argument}} ) async { defer { - _ = __await getInt() // expected-error{{'async' call cannot occur in a defer body}} + _ = await getInt() // expected-error{{'async' call cannot occur in a defer body}} } print("foo") } func test3() { // expected-note{{add 'async' to function 'test3()' to make it asynchronous}} - _ = __await getInt() // expected-error{{'async' in a function that does not support concurrency}} + _ = await getInt() // expected-error{{'async' in a function that does not support concurrency}} } enum SomeEnum: Int { -case foo = __await 5 // expected-error{{raw value for enum case must be a literal}} +case foo = await 5 // expected-error{{raw value for enum case must be a literal}} } struct SomeStruct { - var x = __await getInt() // expected-error{{'async' call cannot occur in a property initializer}} - static var y = __await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}} + var x = await getInt() // expected-error{{'async' call cannot occur in a property initializer}} + static var y = await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}} } func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { } @@ -46,27 +46,27 @@ struct HasAsyncBad { } func testAutoclosure() async { - __await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} - __await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} + await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} - __await acceptAutoclosureAsync(__await getInt()) - __await acceptAutoclosureNonAsync(__await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + await acceptAutoclosureAsync(await getInt()) + await acceptAutoclosureNonAsync(await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} - __await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} - __await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} + await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} + await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} } // Test inference of 'async' from the body of a closure. func testClosure() { let closure = { - __await getInt() + await getInt() } let _: () -> Int = closure // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} let closure2 = { () async -> Int in print("here") - return __await getInt() + return await getInt() } let _: () -> Int = closure2 // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py index 7f26bce1de463..59801e8e98244 100644 --- a/utils/gyb_syntax_support/ExprNodes.py +++ b/utils/gyb_syntax_support/ExprNodes.py @@ -49,7 +49,9 @@ # await foo() Node('AwaitExpr', kind='Expr', children=[ - Child('AwaitKeyword', kind='AwaitToken'), + Child('AwaitKeyword', kind='IdentifierToken', + classification='Keyword', + text_choices=['await']), Child('Expression', kind='Expr'), ]), diff --git a/utils/gyb_syntax_support/Token.py b/utils/gyb_syntax_support/Token.py index 5abe6794e61d7..6a2eb85ac5318 100644 --- a/utils/gyb_syntax_support/Token.py +++ b/utils/gyb_syntax_support/Token.py @@ -196,7 +196,6 @@ def macro_name(self): ExprKeyword('True', 'true', serialization_code=51), ExprKeyword('Try', 'try', serialization_code=52), ExprKeyword('Throws', 'throws', serialization_code=53), - ExprKeyword('Await', '__await', serialization_code=123), Keyword('__FILE__', '__FILE__', serialization_code=54), Keyword('__LINE__', '__LINE__', serialization_code=55), From fc164ce098097f2da7f007b701f9a63480c49396 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 13 Aug 2020 08:29:09 -0700 Subject: [PATCH 119/663] IRGen: be less aggressive about applying COMDAT COMDAT can only be applied to definitions, not declarations. This manifested in builds of llbuild with SwiftPM on Windows. The nominal type descriptor accessor declaration was marked as COMDAT. --- include/swift/IRGen/Linking.h | 15 +++++++++------ lib/IRGen/GenDecl.cpp | 10 ++++++---- lib/IRGen/GenKeyPath.cpp | 2 +- lib/IRGen/GenMeta.cpp | 2 +- test/IRGen/Inputs/comdat1.swift | 5 +++++ test/IRGen/Inputs/comdat2.swift | 4 ++++ test/IRGen/comdat.swift | 14 ++++++++++++++ 7 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 test/IRGen/Inputs/comdat1.swift create mode 100644 test/IRGen/Inputs/comdat2.swift create mode 100644 test/IRGen/comdat.swift diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index d2ee3fba83fff..1f91e09afc8c1 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -1231,7 +1231,7 @@ class ApplyIRLinkage { IRLinkage IRL; public: ApplyIRLinkage(IRLinkage IRL) : IRL(IRL) {} - void to(llvm::GlobalValue *GV) const { + void to(llvm::GlobalValue *GV, bool definition = true) const { llvm::Module *M = GV->getParent(); const llvm::Triple Triple(M->getTargetTriple()); @@ -1244,11 +1244,14 @@ class ApplyIRLinkage { if (Triple.isOSBinFormatELF()) return; - if (IRL.Linkage == llvm::GlobalValue::LinkOnceODRLinkage || - IRL.Linkage == llvm::GlobalValue::WeakODRLinkage) - if (Triple.supportsCOMDAT()) - if (llvm::GlobalObject *GO = dyn_cast(GV)) - GO->setComdat(M->getOrInsertComdat(GV->getName())); + // COMDATs cannot be applied to declarations. If we have a definition, + // apply the COMDAT. + if (definition) + if (IRL.Linkage == llvm::GlobalValue::LinkOnceODRLinkage || + IRL.Linkage == llvm::GlobalValue::WeakODRLinkage) + if (Triple.supportsCOMDAT()) + if (llvm::GlobalObject *GO = dyn_cast(GV)) + GO->setComdat(M->getOrInsertComdat(GV->getName())); } }; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index b5fbcef362e4e..9848d27963e5b 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2024,8 +2024,10 @@ llvm::Function *irgen::createFunction(IRGenModule &IGM, IGM.Module.getFunctionList().push_back(fn); } - ApplyIRLinkage({linkInfo.getLinkage(), linkInfo.getVisibility(), linkInfo.getDLLStorage()}) - .to(fn); + ApplyIRLinkage({linkInfo.getLinkage(), + linkInfo.getVisibility(), + linkInfo.getDLLStorage()}) + .to(fn, linkInfo.isForDefinition()); llvm::AttrBuilder initialAttrs; IGM.constructInitialFnAttributes(initialAttrs, FuncOptMode); @@ -2082,7 +2084,7 @@ llvm::GlobalVariable *swift::irgen::createVariable( ApplyIRLinkage({linkInfo.getLinkage(), linkInfo.getVisibility(), linkInfo.getDLLStorage()}) - .to(var); + .to(var, linkInfo.isForDefinition()); var->setAlignment(llvm::MaybeAlign(alignment.getValue())); // Everything externally visible is considered used in Swift. @@ -4742,7 +4744,7 @@ IRGenModule::getAddrOfWitnessTableLazyAccessFunction( LinkInfo link = LinkInfo::get(*this, entity, forDefinition); entry = createFunction(*this, link, signature); ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()}) - .to(entry); + .to(entry, link.isForDefinition()); return entry; } diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 6cfc8d962c9b9..a1c0d88161585 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -1329,7 +1329,7 @@ void IRGenModule::emitSILProperty(SILProperty *prop) { ApplyIRLinkage({linkInfo.getLinkage(), linkInfo.getVisibility(), llvm::GlobalValue::DLLExportStorageClass}) - .to(GA); + .to(GA, linkInfo.isForDefinition()); } return; } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index e6812490abbff..c86d788ac8f29 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -3635,7 +3635,7 @@ static void emitObjCClassSymbol(IRGenModule &IGM, ptrTy->getElementType(), ptrTy->getAddressSpace(), link.getLinkage(), link.getName(), metadata, &IGM.Module); ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()}) - .to(alias); + .to(alias, link.isForDefinition()); } /// Emit the type metadata or metadata template for a class. diff --git a/test/IRGen/Inputs/comdat1.swift b/test/IRGen/Inputs/comdat1.swift new file mode 100644 index 0000000000000..f219fa273491d --- /dev/null +++ b/test/IRGen/Inputs/comdat1.swift @@ -0,0 +1,5 @@ +private final class C {} +public func f() { + var cs: [C] = [] + cs.append(C()) +} diff --git a/test/IRGen/Inputs/comdat2.swift b/test/IRGen/Inputs/comdat2.swift new file mode 100644 index 0000000000000..96f5838138883 --- /dev/null +++ b/test/IRGen/Inputs/comdat2.swift @@ -0,0 +1,4 @@ +public func g() { + var a: [Int] = [] + a.append(1) +} diff --git a/test/IRGen/comdat.swift b/test/IRGen/comdat.swift new file mode 100644 index 0000000000000..e85eb939af45b --- /dev/null +++ b/test/IRGen/comdat.swift @@ -0,0 +1,14 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-ir %S/Inputs/comdat1.swift %S/Inputs/comdat2.swift -O -num-threads 1 -module-name comdat -o %t/comdat1.ll -o %t/comdat2.ll +// RUN: %FileCheck -check-prefix CHECK-1 %s < %t/comdat1.ll +// RUN: %FileCheck -check-prefix CHECK-2 %s < %t/comdat2.ll + +// REQUIRES: OS=windows-msvc + +// Ensure that the definition is marked as COMDAT +// CHECK-1: "$s6comdat1C33_{{.*}}LLCMa" = comdat any +// CHECK-1: "$s6comdat1C33_{{.*}}LLCMn" = comdat any + +// Ensure that no foward declaration is emitted +// CHECK-2-NOT: "$s6comdat1C33_{{.*}}LLCMa" = comdat any +// CHECK-2-NOT: "$s6comdat1C33_{{.*}}LLCMn" = comdat any From d52a159903dd1b5c6a19b7248fb2644b091d1322 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Thu, 13 Aug 2020 12:28:31 -0700 Subject: [PATCH 120/663] Remove old symlink before creating new symlink --- utils/recursive-lipo | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/recursive-lipo b/utils/recursive-lipo index 056b5f3576ef6..df3d302e651fd 100755 --- a/utils/recursive-lipo +++ b/utils/recursive-lipo @@ -63,6 +63,9 @@ def merge_lipo_files(src_root_dirs, file_list, copy_verbatim_subpaths, if all([os.path.islink(item) for item in file_paths]): # It's a symlink in all found instances, copy the link. print("-- Creating symlink %s" % dest_path) + # Remove symlink if it already exists + if os.path.islink(dest_path): + os.remove(dest_path) os.symlink(os.readlink(file_paths[0]), dest_path) elif all([os.path.isdir(item) for item in file_paths]): # It's a subdir in all found instances. From cbb1fd3f27de41b2dd78251327c580f441a89889 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 13 Aug 2020 15:03:40 -0400 Subject: [PATCH 121/663] Add some comments to ConcurrentReadableArrayTest.MultiThreaded. Add a second test to stress the snapshot code. --- unittests/runtime/Concurrent.cpp | 67 +++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/unittests/runtime/Concurrent.cpp b/unittests/runtime/Concurrent.cpp index 24a25a0d001f6..00f09675d6958 100644 --- a/unittests/runtime/Concurrent.cpp +++ b/unittests/runtime/Concurrent.cpp @@ -56,12 +56,15 @@ TEST(ConcurrentReadableArrayTest, MultiThreaded) { }; ConcurrentReadableArray array; + // The writers will append values with their thread number and increasing + // values of x. auto writer = [&](int threadNumber) { for (int i = 0; i < insertCount; i++) array.push_back({ threadNumber, i }); }; auto reader = [&] { + // Track the maximum value we've seen for each writer thread. int maxByThread[writerCount]; bool done = false; while (!done) { @@ -69,9 +72,15 @@ TEST(ConcurrentReadableArrayTest, MultiThreaded) { maxByThread[i] = -1; for (auto element : array.snapshot()) { ASSERT_LT(element.threadNumber, writerCount); + // Each element we see must be larger than the maximum element we've + // previously seen for that writer thread, otherwise that means that + // we're seeing mutations out of order. ASSERT_GT(element.x, maxByThread[element.threadNumber]); maxByThread[element.threadNumber] = element.x; } + + // If the max for each thread is the max that'll be inserted, then we're + // done and should exit. done = true; for (int i = 0; i < writerCount; i++) { if (maxByThread[i] < insertCount - 1) @@ -87,5 +96,61 @@ TEST(ConcurrentReadableArrayTest, MultiThreaded) { reader(); }); - ASSERT_EQ(array.snapshot().count(), writerCount * insertCount); + ASSERT_EQ(array.snapshot().count(), (size_t)writerCount * insertCount); +} + +TEST(ConcurrentReadableArrayTest, MultiThreaded2) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 100000; + + struct Value { + int threadNumber; + int x; + }; + ConcurrentReadableArray array; + + // The writers will append values with their thread number and increasing + // values of x. + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + array.push_back({ threadNumber, i }); + }; + + auto reader = [&] { + // Track the maximum value we've seen for each writer thread. + int maxByThread[writerCount]; + for (int i = 0; i < writerCount; i++) + maxByThread[i] = -1; + bool done = false; + while (!done) { + auto snapshot = array.snapshot(); + // Don't do anything until some data is actually added. + if (snapshot.count() == 0) + continue; + + // Grab the last element in the snapshot. + auto element = snapshot.begin()[snapshot.count() - 1]; + ASSERT_LT(element.threadNumber, writerCount); + // Each element we see must be equal to or larger than the maximum element + // we've previously seen for that writer thread, otherwise that means that + // we're seeing mutations out of order. + ASSERT_GE(element.x, maxByThread[element.threadNumber]); + maxByThread[element.threadNumber] = element.x; + + // We'll eventually see some thread add its maximum value. We'll call it + // done when we reach that point. + if (element.x == insertCount - 1) + done = true; + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); + + ASSERT_EQ(array.snapshot().count(), (size_t)writerCount * insertCount); } From 90f5730026aea1da0acbc6a9b1d6a62ebfaa2c80 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 13 Aug 2020 12:43:34 -0700 Subject: [PATCH 122/663] [NFC] Refactor getNativeSILFunctionType to use a lambda. (#33440) --- lib/SIL/IR/SILFunctionType.cpp | 41 ++++++++++++++-------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 5fe7a5d592ae3..edc876b9a2851 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -2400,6 +2400,12 @@ static CanSILFunctionType getNativeSILFunctionType( Optional reqtSubs, ProtocolConformanceRef witnessMethodConformance) { assert(bool(origConstant) == bool(constant)); + auto getSILFunctionTypeForConventions = + [&](const Conventions &convs) -> CanSILFunctionType { + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, convs, ForeignInfo(), origConstant, + constant, reqtSubs, witnessMethodConformance); + }; switch (extInfo.getSILRepresentation()) { case SILFunctionType::Representation::Block: case SILFunctionType::Representation::CFunctionPointer: @@ -2416,42 +2422,29 @@ static CanSILFunctionType getNativeSILFunctionType( switch (constant ? constant->kind : SILDeclRef::Kind::Func) { case SILDeclRef::Kind::Initializer: case SILDeclRef::Kind::EnumElement: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultInitializerConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); + return getSILFunctionTypeForConventions(DefaultInitializerConventions()); case SILDeclRef::Kind::Allocator: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultAllocatorConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); - case SILDeclRef::Kind::Func: + return getSILFunctionTypeForConventions(DefaultAllocatorConventions()); + case SILDeclRef::Kind::Func: { // If we have a setter, use the special setter convention. This ensures // that we take normal parameters at +1. if (constant && constant->isSetter()) { - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DefaultSetterConventions(), - ForeignInfo(), origConstant, constant, - reqtSubs, witnessMethodConformance); + return getSILFunctionTypeForConventions(DefaultSetterConventions()); } - LLVM_FALLTHROUGH; + return getSILFunctionTypeForConventions( + DefaultConventions(NormalParameterConvention::Guaranteed)); + } case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::DefaultArgGenerator: case SILDeclRef::Kind::StoredPropertyInitializer: case SILDeclRef::Kind::PropertyWrapperBackingInitializer: case SILDeclRef::Kind::IVarInitializer: - case SILDeclRef::Kind::IVarDestroyer: { - auto conv = DefaultConventions(NormalParameterConvention::Guaranteed); - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, conv, ForeignInfo(), origConstant, - constant, reqtSubs, witnessMethodConformance); - } + case SILDeclRef::Kind::IVarDestroyer: + return getSILFunctionTypeForConventions( + DefaultConventions(NormalParameterConvention::Guaranteed)); case SILDeclRef::Kind::Deallocator: - return getSILFunctionType(TC, context, origType, substInterfaceType, - extInfo, DeallocatorConventions(), - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); + return getSILFunctionTypeForConventions(DeallocatorConventions()); } } } From 1e940c2c7ef5b11982a1985eb953aa23a28c6ffa Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Thu, 13 Aug 2020 06:26:20 -0400 Subject: [PATCH 123/663] [NFC] Fix -Wsuggest-override warnings LLVM, as of 77e0e9e17daf0865620abcd41f692ab0642367c4, now builds with -Wsuggest-override. Let's clean up the swift sources rather than disable the warning locally. --- include/swift/AST/ASTPrinter.h | 2 +- include/swift/AST/ClangModuleLoader.h | 2 +- include/swift/AST/Evaluator.h | 6 +- include/swift/AST/NameLookup.h | 2 +- include/swift/AST/PrettyStackTrace.h | 24 +++---- include/swift/Driver/Action.h | 26 +++---- include/swift/Reflection/TypeLowering.h | 6 +- include/swift/SIL/OptimizationRemark.h | 1 - include/swift/SIL/PrettyStackTrace.h | 6 +- include/swift/SIL/SILConstants.h | 2 +- include/swift/SIL/SILDebuggerClient.h | 4 +- .../swift/SIL/SILOpenedArchetypesTracker.h | 4 +- .../PassManager/PrettyStackTrace.h | 4 +- .../SILOptimizer/Utils/LoadStoreOptUtils.h | 4 +- lib/AST/Decl.cpp | 4 +- lib/AST/Expr.cpp | 4 +- lib/AST/InlinableText.cpp | 2 +- lib/AST/Module.cpp | 4 +- lib/AST/Pattern.cpp | 4 +- lib/AST/ProtocolConformance.cpp | 4 +- lib/AST/Stmt.cpp | 4 +- lib/AST/TypeRepr.cpp | 4 +- .../ClangModuleDependencyScanner.cpp | 4 +- lib/ClangImporter/ImportDecl.cpp | 4 +- lib/IDE/ConformingMethodList.cpp | 2 +- lib/IDE/Refactoring.cpp | 28 ++++---- lib/IDE/TypeContextInfo.cpp | 2 +- lib/SIL/IR/SILFunction.cpp | 4 +- .../Transforms/CopyForwarding.cpp | 16 ++--- lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/CSDiagnostics.h | 8 +-- lib/Sema/CSFix.h | 40 +++++------ lib/Sema/TypeCheckConstraints.cpp | 4 +- lib/SymbolGraphGen/SymbolGraphASTWalker.h | 2 +- stdlib/public/Reflection/TypeLowering.cpp | 28 ++++---- stdlib/public/runtime/ReflectionMirror.mm | 69 +++++++++---------- 36 files changed, 167 insertions(+), 169 deletions(-) diff --git a/include/swift/AST/ASTPrinter.h b/include/swift/AST/ASTPrinter.h index 3c28d725ab6bb..3273d3ec4d7f4 100644 --- a/include/swift/AST/ASTPrinter.h +++ b/include/swift/AST/ASTPrinter.h @@ -325,7 +325,7 @@ class ExtraIndentStreamPrinter : public StreamPrinter { ExtraIndentStreamPrinter(raw_ostream &out, StringRef extraIndent) : StreamPrinter(out), ExtraIndent(extraIndent) { } - virtual void printIndent() { + virtual void printIndent() override { printText(ExtraIndent); StreamPrinter::printIndent(); } diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index 64bc7e7d58413..06c41a3d8e61e 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -109,7 +109,7 @@ class StableSerializationPath { class ClangModuleLoader : public ModuleLoader { private: - virtual void anchor(); + virtual void anchor() override; protected: using ModuleLoader::ModuleLoader; diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index 5235343ebe779..212682d0bc121 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -65,7 +65,7 @@ class PrettyStackTraceRequest : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceRequest(const Request &request) : request(request) { } - void print(llvm::raw_ostream &out) const { + void print(llvm::raw_ostream &out) const override { out << "While evaluating request "; simple_display(out, request); out << "\n"; @@ -85,9 +85,9 @@ struct CyclicalRequestError : CyclicalRequestError(const Request &request, const Evaluator &evaluator) : request(request), evaluator(evaluator) {} - virtual void log(llvm::raw_ostream &out) const; + virtual void log(llvm::raw_ostream &out) const override; - virtual std::error_code convertToErrorCode() const { + virtual std::error_code convertToErrorCode() const override { // This is essentially unused, but is a temporary requirement for // llvm::ErrorInfo subclasses. llvm_unreachable("shouldn't get std::error_code from CyclicalRequestError"); diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index ea847ce01c1ba..5df02ce9df3a3 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -375,7 +375,7 @@ class LambdaDeclConsumer : public VisibleDeclConsumer { public: LambdaDeclConsumer(Fn &&callback) : Callback(std::move(callback)) {} - void foundDecl(ValueDecl *VD, DeclVisibilityKind reason, DynamicLookupInfo) { + void foundDecl(ValueDecl *VD, DeclVisibilityKind reason, DynamicLookupInfo) override { Callback(VD, reason); } }; diff --git a/include/swift/AST/PrettyStackTrace.h b/include/swift/AST/PrettyStackTrace.h index 51d047ecbb1b5..e08b7bb9aa9d8 100644 --- a/include/swift/AST/PrettyStackTrace.h +++ b/include/swift/AST/PrettyStackTrace.h @@ -51,7 +51,7 @@ class PrettyStackTraceLocation : public llvm::PrettyStackTraceEntry { PrettyStackTraceLocation(const ASTContext &C, const char *action, SourceLoc loc) : Context(C), Loc(loc), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printDeclDescription(llvm::raw_ostream &out, const Decl *D, @@ -65,7 +65,7 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceDecl(const char *action, const Decl *D) : TheDecl(D), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; /// PrettyStackTraceAnyFunctionRef - Observe that we are processing a specific @@ -76,7 +76,7 @@ class PrettyStackTraceAnyFunctionRef : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceAnyFunctionRef(const char *action, AnyFunctionRef ref) : TheRef(ref), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printExprDescription(llvm::raw_ostream &out, Expr *E, @@ -91,7 +91,7 @@ class PrettyStackTraceExpr : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceExpr(const ASTContext &C, const char *action, Expr *E) : Context(C), TheExpr(E), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printStmtDescription(llvm::raw_ostream &out, Stmt *S, @@ -106,7 +106,7 @@ class PrettyStackTraceStmt : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceStmt(const ASTContext &C, const char *action, Stmt *S) : Context(C), TheStmt(S), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printPatternDescription(llvm::raw_ostream &out, Pattern *P, @@ -121,7 +121,7 @@ class PrettyStackTracePattern : public llvm::PrettyStackTraceEntry { public: PrettyStackTracePattern(const ASTContext &C, const char *action, Pattern *P) : Context(C), ThePattern(P), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printTypeDescription(llvm::raw_ostream &out, Type T, @@ -135,7 +135,7 @@ class PrettyStackTraceType : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceType(const ASTContext &C, const char *action, Type type) : Context(C), TheType(type), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; /// PrettyStackTraceClangType - Observe that we are processing a @@ -146,7 +146,7 @@ class PrettyStackTraceClangType : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceClangType(const char *action, const clang::Type *type) : TheType(type), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; /// Observe that we are processing a specific type representation. @@ -158,7 +158,7 @@ class PrettyStackTraceTypeRepr : public llvm::PrettyStackTraceEntry { PrettyStackTraceTypeRepr(const ASTContext &C, const char *action, TypeRepr *type) : Context(C), TheType(type), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; /// PrettyStackTraceConformance - Observe that we are processing a @@ -171,7 +171,7 @@ class PrettyStackTraceConformance : public llvm::PrettyStackTraceEntry { PrettyStackTraceConformance(const ASTContext &C, const char *action, const ProtocolConformance *conformance) : Context(C), Conformance(conformance), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printConformanceDescription(llvm::raw_ostream &out, @@ -217,7 +217,7 @@ class PrettyStackTraceDifferentiabilityWitness PrettyStackTraceDifferentiabilityWitness( const char *action, const SILDifferentiabilityWitnessKey key) : Key(key), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; void printDifferentiabilityWitnessDescription( @@ -232,7 +232,7 @@ class PrettyStackTraceDeclContext : public llvm::PrettyStackTraceEntry { public: PrettyStackTraceDeclContext(const char *action, const DeclContext *DC) : DC(DC), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; } // end namespace swift diff --git a/include/swift/Driver/Action.h b/include/swift/Driver/Action.h index 02801d8aece66..504fc35d33df2 100644 --- a/include/swift/Driver/Action.h +++ b/include/swift/Driver/Action.h @@ -148,7 +148,7 @@ class CompileJobAction : public JobAction { }; private: - virtual void anchor(); + virtual void anchor() override; InputInfo inputInfo; public: @@ -191,7 +191,7 @@ class CompileJobAction : public JobAction { class InterpretJobAction : public JobAction { private: - virtual void anchor(); + virtual void anchor() override; public: explicit InterpretJobAction() @@ -205,7 +205,7 @@ class InterpretJobAction : public JobAction { class BackendJobAction : public JobAction { private: - virtual void anchor(); + virtual void anchor() override; // In case of multi-threaded compilation, the compile-action produces multiple // output bitcode-files. For each bitcode-file a BackendJobAction is created. @@ -220,7 +220,7 @@ class BackendJobAction : public JobAction { return A->getKind() == Action::Kind::BackendJob; } - virtual size_t getInputIndex() const { return InputIndex; } + virtual size_t getInputIndex() const override { return InputIndex; } }; class REPLJobAction : public JobAction { @@ -231,7 +231,7 @@ class REPLJobAction : public JobAction { RequireLLDB }; private: - virtual void anchor(); + virtual void anchor() override; Mode RequestedMode; public: REPLJobAction(Mode mode) @@ -247,7 +247,7 @@ class REPLJobAction : public JobAction { }; class MergeModuleJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: MergeModuleJobAction(ArrayRef Inputs) : JobAction(Action::Kind::MergeModuleJob, Inputs, @@ -259,7 +259,7 @@ class MergeModuleJobAction : public JobAction { }; class ModuleWrapJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: ModuleWrapJobAction(ArrayRef Inputs) : JobAction(Action::Kind::ModuleWrapJob, Inputs, @@ -271,7 +271,7 @@ class ModuleWrapJobAction : public JobAction { }; class AutolinkExtractJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: AutolinkExtractJobAction(ArrayRef Inputs) : JobAction(Action::Kind::AutolinkExtractJob, Inputs, @@ -283,7 +283,7 @@ class AutolinkExtractJobAction : public JobAction { }; class GenerateDSYMJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: explicit GenerateDSYMJobAction(const Action *Input) : JobAction(Action::Kind::GenerateDSYMJob, Input, @@ -295,7 +295,7 @@ class GenerateDSYMJobAction : public JobAction { }; class VerifyDebugInfoJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: explicit VerifyDebugInfoJobAction(const Action *Input) : JobAction(Action::Kind::VerifyDebugInfoJob, Input, @@ -309,7 +309,7 @@ class VerifyDebugInfoJobAction : public JobAction { class GeneratePCHJobAction : public JobAction { std::string PersistentPCHDir; - virtual void anchor(); + virtual void anchor() override; public: GeneratePCHJobAction(const Action *Input, StringRef persistentPCHDir) : JobAction(Action::Kind::GeneratePCHJob, Input, @@ -326,7 +326,7 @@ class GeneratePCHJobAction : public JobAction { }; class DynamicLinkJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; LinkKind Kind; public: @@ -344,7 +344,7 @@ class DynamicLinkJobAction : public JobAction { }; class StaticLinkJobAction : public JobAction { - virtual void anchor(); + virtual void anchor() override; public: StaticLinkJobAction(ArrayRef Inputs, LinkKind K) diff --git a/include/swift/Reflection/TypeLowering.h b/include/swift/Reflection/TypeLowering.h index 13eda217e1510..f3e59d14ac8b3 100644 --- a/include/swift/Reflection/TypeLowering.h +++ b/include/swift/Reflection/TypeLowering.h @@ -181,7 +181,7 @@ class BuiltinTypeInfo : public TypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const; + int *extraInhabitantIndex) const override; static bool classof(const TypeInfo *TI) { return TI->getKind() == TypeInfoKind::Builtin; @@ -208,7 +208,7 @@ class RecordTypeInfo : public TypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const; + int *index) const override; static bool classof(const TypeInfo *TI) { return TI->getKind() == TypeInfoKind::Record; @@ -299,7 +299,7 @@ class ReferenceTypeInfo : public TypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { if (getNumExtraInhabitants() == 0) { *extraInhabitantIndex = -1; return true; diff --git a/include/swift/SIL/OptimizationRemark.h b/include/swift/SIL/OptimizationRemark.h index 47318c4cc6765..32842dabb5543 100644 --- a/include/swift/SIL/OptimizationRemark.h +++ b/include/swift/SIL/OptimizationRemark.h @@ -57,7 +57,6 @@ struct ArgumentKeyKind { InnerTy innerValue; ArgumentKeyKind(InnerTy value) : innerValue(value) {} - ArgumentKeyKind(const ArgumentKeyKind &kind) : innerValue(kind.innerValue) {} operator InnerTy() const { return innerValue; } diff --git a/include/swift/SIL/PrettyStackTrace.h b/include/swift/SIL/PrettyStackTrace.h index 7b62b3d6ec8ac..1b35d3ebf3c7f 100644 --- a/include/swift/SIL/PrettyStackTrace.h +++ b/include/swift/SIL/PrettyStackTrace.h @@ -39,7 +39,7 @@ class PrettyStackTraceSILLocation : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILLocation(const char *action, SILLocation loc, ASTContext &C) : Loc(loc), Action(action), Context(C) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; @@ -62,7 +62,7 @@ class PrettyStackTraceSILFunction : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILFunction(llvm::Twine &&twine, const SILFunction *func) : func(func), data(), action(twine.toNullTerminatedStringRef(data)) {} - virtual void print(llvm::raw_ostream &os) const; + virtual void print(llvm::raw_ostream &os) const override; protected: void printFunctionInfo(llvm::raw_ostream &out) const; @@ -77,7 +77,7 @@ class PrettyStackTraceSILNode : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILNode(const char *action, const SILNode *node) : Node(node), Action(action) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; } // end namespace swift diff --git a/include/swift/SIL/SILConstants.h b/include/swift/SIL/SILConstants.h index 4e04f3e8044e7..eb53bad64701f 100644 --- a/include/swift/SIL/SILConstants.h +++ b/include/swift/SIL/SILConstants.h @@ -73,7 +73,7 @@ class SymbolicValueBumpAllocator : public SymbolicValueAllocator { SymbolicValueBumpAllocator() {} ~SymbolicValueBumpAllocator() {} - void *allocate(unsigned long byteSize, unsigned alignment) { + void *allocate(unsigned long byteSize, unsigned alignment) override { return bumpAllocator.Allocate(byteSize, alignment); } }; diff --git a/include/swift/SIL/SILDebuggerClient.h b/include/swift/SIL/SILDebuggerClient.h index e6c2bf7a2bd27..1f8af82d78fb1 100644 --- a/include/swift/SIL/SILDebuggerClient.h +++ b/include/swift/SIL/SILDebuggerClient.h @@ -38,11 +38,11 @@ class SILDebuggerClient : public DebuggerClient { virtual SILValue emitLValueForVariable(VarDecl *var, SILBuilder &builder) = 0; - inline SILDebuggerClient *getAsSILDebuggerClient() { + inline SILDebuggerClient *getAsSILDebuggerClient() override { return this; } private: - virtual void anchor(); + virtual void anchor() override; }; } // namespace swift diff --git a/include/swift/SIL/SILOpenedArchetypesTracker.h b/include/swift/SIL/SILOpenedArchetypesTracker.h index 508eb366cdcf9..6c89487ceb4b9 100644 --- a/include/swift/SIL/SILOpenedArchetypesTracker.h +++ b/include/swift/SIL/SILOpenedArchetypesTracker.h @@ -99,10 +99,10 @@ class SILOpenedArchetypesTracker : public DeleteNotificationHandler { bool hasUnresolvedOpenedArchetypeDefinitions(); // Handling of instruction removal notifications. - bool needsNotifications() { return true; } + bool needsNotifications() override { return true; } // Handle notifications about removals of instructions. - void handleDeleteNotification(SILNode *node); + void handleDeleteNotification(SILNode *node) override; // Dump the contents. void dump() const; diff --git a/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h b/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h index f00bba619e533..1ebae9671d7da 100644 --- a/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h +++ b/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h @@ -30,7 +30,7 @@ class PrettyStackTraceSILFunctionTransform PrettyStackTraceSILFunctionTransform(SILFunctionTransform *SFT, unsigned PassNumber); - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; class PrettyStackTraceSILModuleTransform : public llvm::PrettyStackTraceEntry { @@ -41,7 +41,7 @@ class PrettyStackTraceSILModuleTransform : public llvm::PrettyStackTraceEntry { PrettyStackTraceSILModuleTransform(SILModuleTransform *SMT, unsigned PassNumber) : SMT(SMT), PassNumber(PassNumber) {} - virtual void print(llvm::raw_ostream &OS) const; + virtual void print(llvm::raw_ostream &OS) const override; }; } // end namespace swift diff --git a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h index 39b3c6ffa9ad1..cee8fd7ed8bc1 100644 --- a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h +++ b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h @@ -236,7 +236,7 @@ class LSValue : public LSBase { } /// Returns whether the LSValue has been initialized properly. - bool isValid() const { + bool isValid() const override { if (CoveringValue) return true; return LSBase::isValid(); @@ -261,7 +261,7 @@ class LSValue : public LSBase { return Path.getValue().createExtract(Base, Inst, true); } - void print(llvm::raw_ostream &os) { + void print(llvm::raw_ostream &os) override { if (CoveringValue) { os << "Covering Value"; return; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4081ce38025e9..250ddaeef207d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7923,7 +7923,7 @@ void Decl::setClangNode(ClangNode Node) { // dependency. struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Decl *D = static_cast(Entity); @@ -7936,7 +7936,7 @@ struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Decl *D = static_cast(Entity); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 59cdfa8ab7cb7..95a290a0d303c 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2470,14 +2470,14 @@ SourceLoc swift::extractNearestSourceLoc(const DefaultArgumentExpr *expr) { // dependency. struct ExprTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Expr *E = static_cast(Entity); OS << Expr::getKindName(E->getKind()); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Expr *E = static_cast(Entity); diff --git a/lib/AST/InlinableText.cpp b/lib/AST/InlinableText.cpp index 7a805d94add6d..c21a0b10e217c 100644 --- a/lib/AST/InlinableText.cpp +++ b/lib/AST/InlinableText.cpp @@ -78,7 +78,7 @@ struct ExtractInactiveRanges : public ASTWalker { ranges.push_back(charRange); } - bool walkToDeclPre(Decl *d) { + bool walkToDeclPre(Decl *d) override { auto icd = dyn_cast(d); if (!icd) return true; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 34a9d40705693..7ffb167d69800 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2657,14 +2657,14 @@ const clang::Module* ModuleEntity::getAsClangModule() const { // dependency. struct SourceFileTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const SourceFile *SF = static_cast(Entity); OS << llvm::sys::path::filename(SF->getFilename()); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { // SourceFiles don't have SourceLocs of their own; they contain them. } }; diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp index 2006c06e62e27..eed9e33c0341c 100644 --- a/lib/AST/Pattern.cpp +++ b/lib/AST/Pattern.cpp @@ -517,7 +517,7 @@ SourceRange ExprPattern::getSourceRange() const { // dependency. struct PatternTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Pattern *P = static_cast(Entity); @@ -526,7 +526,7 @@ struct PatternTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Pattern *P = static_cast(Entity); diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index d612dff6a0574..5b2ff91752ca6 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -1489,7 +1489,7 @@ ProtocolConformanceRef::getCanonicalConformanceRef() const { struct ProtocolConformanceTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const ProtocolConformance *C = @@ -1497,7 +1497,7 @@ struct ProtocolConformanceTraceFormatter C->printName(OS); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const ProtocolConformance *C = diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 83d24aacaf94a..98541beee21a4 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -524,14 +524,14 @@ SwitchStmt *SwitchStmt::create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, // dependency. struct StmtTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Stmt *S = static_cast(Entity); OS << Stmt::getKindName(S->getKind()); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Stmt *S = static_cast(Entity); diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 0a28f865f8e88..bb7e6e65f74e5 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -454,14 +454,14 @@ void SILBoxTypeRepr::printImpl(ASTPrinter &Printer, // linkage dependency. struct TypeReprTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const TypeRepr *TR = static_cast(Entity); TR->print(OS); } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const TypeRepr *TR = static_cast(Entity); diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index 6c44002d46dbb..ed49b5213ead5 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -87,11 +87,11 @@ namespace { : Command(std::move(Cmd)) {} virtual std::vector - getCompileCommands(StringRef FilePath) const { + getCompileCommands(StringRef FilePath) const override { return {Command}; } - virtual std::vector getAllCompileCommands() const { + virtual std::vector getAllCompileCommands() const override { return {Command}; } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e35b0aed470b7..7f40d1a6de44c 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -8885,7 +8885,7 @@ ClangImporter::getEnumConstantName(const clang::EnumConstantDecl *enumConstant){ // linkage dependency. struct ClangDeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const clang::Decl *CD = static_cast(Entity); @@ -8908,7 +8908,7 @@ struct ClangDeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; if (CSM) { diff --git a/lib/IDE/ConformingMethodList.cpp b/lib/IDE/ConformingMethodList.cpp index 9a843b82f0cc0..f1fcf9f6f00e0 100644 --- a/lib/IDE/ConformingMethodList.cpp +++ b/lib/IDE/ConformingMethodList.cpp @@ -154,7 +154,7 @@ void ConformingMethodListCallbacks::getMatchingMethods( Result(result) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind reason, - DynamicLookupInfo) { + DynamicLookupInfo) override { if (isMatchingMethod(VD) && !VD->shouldHideFromEditor()) Result.push_back(VD); } diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index 8c6bdcc01143e..e7838a606ce3e 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -1711,7 +1711,7 @@ class FindAllSubDecls : public SourceEntityWalker { FindAllSubDecls(llvm::SmallPtrSetImpl &found) : Found(found) {} - bool walkToDeclPre(Decl *D, CharSourceRange range) { + bool walkToDeclPre(Decl *D, CharSourceRange range) override { // Record this Decl, and skip its contents if we've already touched it. if (!Found.insert(D).second) return false; @@ -1876,7 +1876,7 @@ findConcatenatedExpressions(ResolvedRangeInfo Info, ASTContext &Ctx) { return true; } - bool walkToExprPre(Expr *E) { + bool walkToExprPre(Expr *E) override { if (E->isImplicit()) return true; // FIXME: we should have ErrorType instead of null. @@ -2001,13 +2001,13 @@ class ExpandableAssignTernaryExprInfo: public ExpandableTernaryExprInfo { public: ExpandableAssignTernaryExprInfo(AssignExpr *Assign): Assign(Assign) {} - IfExpr *getIf() { + IfExpr *getIf() override { if (!Assign) return nullptr; return dyn_cast_or_null(Assign->getSrc()); } - SourceRange getNameRange() { + SourceRange getNameRange() override { auto Invalid = SourceRange(); if (!Assign) @@ -2019,7 +2019,7 @@ class ExpandableAssignTernaryExprInfo: public ExpandableTernaryExprInfo { return Invalid; } - Type getType() { + Type getType() override { return nullptr; } @@ -2035,7 +2035,7 @@ class ExpandableBindingTernaryExprInfo: public ExpandableTernaryExprInfo { ExpandableBindingTernaryExprInfo(PatternBindingDecl *Binding): Binding(Binding) {} - IfExpr *getIf() { + IfExpr *getIf() override { if (Binding && Binding->getNumPatternEntries() == 1) { if (auto *Init = Binding->getInit(0)) { return dyn_cast(Init); @@ -2045,14 +2045,14 @@ class ExpandableBindingTernaryExprInfo: public ExpandableTernaryExprInfo { return nullptr; } - SourceRange getNameRange() { + SourceRange getNameRange() override { if (auto Pattern = getNamePattern()) return Pattern->getSourceRange(); return SourceRange(); } - Type getType() { + Type getType() override { if (auto Pattern = getNamePattern()) return Pattern->getType(); @@ -2347,7 +2347,7 @@ isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) { bool ConditionUseOnlyAllowedFunctions = false; StringRef ExpectName; - Expr *walkToExprPost(Expr *E) { + Expr *walkToExprPost(Expr *E) override { if (E->getKind() != ExprKind::DeclRef) return E; auto D = dyn_cast(E)->getDecl(); @@ -2446,7 +2446,7 @@ bool RefactoringActionConvertToSwitchStmt::performChange() { public: std::string VarName; - Expr *walkToExprPost(Expr *E) { + Expr *walkToExprPost(Expr *E) override { if (E->getKind() != ExprKind::DeclRef) return E; auto D = dyn_cast(E)->getDecl(); @@ -2463,7 +2463,7 @@ bool RefactoringActionConvertToSwitchStmt::performChange() { SmallString<64> ConditionalPattern = SmallString<64>(); - Expr *walkToExprPost(Expr *E) { + Expr *walkToExprPost(Expr *E) override { if (E->getKind() != ExprKind::Binary) return E; auto BE = dyn_cast(E); @@ -2472,7 +2472,7 @@ bool RefactoringActionConvertToSwitchStmt::performChange() { return E; } - std::pair walkToPatternPre(Pattern *P) { + std::pair walkToPatternPre(Pattern *P) override { ConditionalPattern.append(Lexer::getCharSourceRangeFromSourceRange(SM, P->getSourceRange()).str()); if (P->getKind() == PatternKind::OptionalSome) ConditionalPattern.append("?"); @@ -2705,7 +2705,7 @@ findConvertToTernaryExpression(ResolvedRangeInfo Info) { walk(S); } - virtual bool walkToExprPre(Expr *E) { + virtual bool walkToExprPre(Expr *E) override { Assign = dyn_cast(E); return false; } @@ -3086,7 +3086,7 @@ static Expr *findLocalizeTarget(ResolvedCursorInfo CursorInfo) { SourceLoc StartLoc; Expr *Target; StringLiteralFinder(SourceLoc StartLoc): StartLoc(StartLoc), Target(nullptr) {} - bool walkToExprPre(Expr *E) { + bool walkToExprPre(Expr *E) override { if (E->getStartLoc() != StartLoc) return false; if (E->getKind() == ExprKind::InterpolatedStringLiteral) diff --git a/lib/IDE/TypeContextInfo.cpp b/lib/IDE/TypeContextInfo.cpp index aacaa875d96b3..0ab8242b7aa34 100644 --- a/lib/IDE/TypeContextInfo.cpp +++ b/lib/IDE/TypeContextInfo.cpp @@ -158,7 +158,7 @@ void ContextInfoCallbacks::getImplicitMembers( : DC(DC), CurModule(DC->getParentModule()), T(T), Result(Result) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason, - DynamicLookupInfo) { + DynamicLookupInfo) override { if (canBeImplictMember(VD) && !VD->shouldHideFromEditor()) Result.push_back(VD); } diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index f5e27bbd56c1b..8f4d425549d02 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -629,7 +629,7 @@ void SILFunction::setObjCReplacement(Identifier replacedFunc) { // linkage dependency. struct SILFunctionTraceFormatter : public UnifiedStatsReporter::TraceFormatter { - void traceName(const void *Entity, raw_ostream &OS) const { + void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const SILFunction *F = static_cast(Entity); @@ -637,7 +637,7 @@ struct SILFunctionTraceFormatter : public UnifiedStatsReporter::TraceFormatter { } void traceLoc(const void *Entity, SourceManager *SM, - clang::SourceManager *CSM, raw_ostream &OS) const { + clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const SILFunction *F = static_cast(Entity); diff --git a/lib/SILOptimizer/Transforms/CopyForwarding.cpp b/lib/SILOptimizer/Transforms/CopyForwarding.cpp index f930a10dc92e0..ad7a41d52f5ad 100644 --- a/lib/SILOptimizer/Transforms/CopyForwarding.cpp +++ b/lib/SILOptimizer/Transforms/CopyForwarding.cpp @@ -537,7 +537,7 @@ class CopyForwarding { public: CopySrcUserVisitor(CopyForwarding &CPF) : CPF(CPF) {} - virtual bool visitNormalUse(SILInstruction *user) { + virtual bool visitNormalUse(SILInstruction *user) override { if (isa(user)) CPF.IsSrcLoadedFrom = true; @@ -549,18 +549,18 @@ class CopyForwarding { // Bail on multiple uses in the same instruction to avoid complexity. return CPF.SrcUserInsts.insert(user).second; } - virtual bool visitTake(CopyAddrInst *take) { + virtual bool visitTake(CopyAddrInst *take) override { if (take->getSrc() == take->getDest()) return false; CPF.TakePoints.push_back(take); return true; } - virtual bool visitDestroy(DestroyAddrInst *destroy) { + virtual bool visitDestroy(DestroyAddrInst *destroy) override { CPF.DestroyPoints.push_back(destroy); return true; } - virtual bool visitDebugValue(DebugValueAddrInst *debugValue) { + virtual bool visitDebugValue(DebugValueAddrInst *debugValue) override { return CPF.SrcDebugValueInsts.insert(debugValue).second; } }; @@ -635,17 +635,17 @@ class CopyDestUserVisitor : public AddressUserVisitor { CopyDestUserVisitor(SmallPtrSetImpl &DestUsers) : DestUsers(DestUsers) {} - virtual bool visitNormalUse(SILInstruction *user) { + virtual bool visitNormalUse(SILInstruction *user) override { // Bail on multiple uses in the same instruction to avoid complexity. return DestUsers.insert(user).second; } - virtual bool visitTake(CopyAddrInst *take) { + virtual bool visitTake(CopyAddrInst *take) override { return DestUsers.insert(take).second; } - virtual bool visitDestroy(DestroyAddrInst *destroy) { + virtual bool visitDestroy(DestroyAddrInst *destroy) override { return DestUsers.insert(destroy).second; } - virtual bool visitDebugValue(DebugValueAddrInst *debugValue) { + virtual bool visitDebugValue(DebugValueAddrInst *debugValue) override { return DestUsers.insert(debugValue).second; } }; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 4791518b68816..09087ae89470a 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1177,7 +1177,7 @@ class VarDeclMultipleReferencesChecker : public ASTWalker { VarDecl *varDecl; int count; - std::pair walkToExprPre(Expr *E) { + std::pair walkToExprPre(Expr *E) override { if (auto *DRE = dyn_cast(E)) { if (DRE->getDecl() == varDecl) ++count; diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 30192dbc20fc4..9786056f334a9 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -2013,7 +2013,7 @@ class MissingContextualBaseInMemberRefFailure final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator), MemberName(member) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; class UnableToInferClosureParameterType final : public FailureDiagnostic { @@ -2022,7 +2022,7 @@ class UnableToInferClosureParameterType final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; class UnableToInferClosureReturnType final : public FailureDiagnostic { @@ -2031,7 +2031,7 @@ class UnableToInferClosureReturnType final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; class UnableToInferProtocolLiteralType final : public FailureDiagnostic { @@ -2065,7 +2065,7 @@ class MissingQuialifierInMemberRefFailure final : public FailureDiagnostic { ConstraintLocator *locator) : FailureDiagnostic(solution, locator) {} - bool diagnoseAsError(); + bool diagnoseAsError() override; }; /// Emits a warning about an attempt to use the 'as' operator as the 'as!' diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index ae232f33ff187..8ce3c43a103af 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -1694,9 +1694,9 @@ class CoerceToCheckedCast final : public ContextualMismatch { locator) {} public: - std::string getName() const { return "as to as!"; } + std::string getName() const override { return "as to as!"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static CoerceToCheckedCast *attempt(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator); @@ -1707,11 +1707,11 @@ class RemoveInvalidCall final : public ConstraintFix { : ConstraintFix(cs, FixKind::RemoveCall, locator) {} public: - std::string getName() const { + std::string getName() const override { return "remove extraneous call from value of non-function type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static RemoveInvalidCall *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1749,13 +1749,13 @@ class SpecifyBaseTypeForContextualMember final : public ConstraintFix { MemberName(member) {} public: - std::string getName() const { + std::string getName() const override { const auto baseName = MemberName.getBaseName(); return "specify base type in reference to member '" + baseName.userFacingName().str() + "'"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyBaseTypeForContextualMember * create(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator); @@ -1766,9 +1766,9 @@ class SpecifyClosureParameterType final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyClosureParameterType, locator) {} public: - std::string getName() const; + std::string getName() const override; - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyClosureParameterType *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1779,11 +1779,11 @@ class SpecifyClosureReturnType final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyClosureReturnType, locator) {} public: - std::string getName() const { + std::string getName() const override { return "specify closure return type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyClosureReturnType *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1794,11 +1794,11 @@ class SpecifyObjectLiteralTypeImport final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyObjectLiteralTypeImport, locator) {} public: - std::string getName() const { + std::string getName() const override { return "import required module to gain access to a default literal type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyObjectLiteralTypeImport *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1810,11 +1810,11 @@ class AddQualifierToAccessTopLevelName final : public ConstraintFix { : ConstraintFix(cs, FixKind::AddQualifierToAccessTopLevelName, locator) {} public: - std::string getName() const { + std::string getName() const override { return "qualify reference to access top-level function"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static AddQualifierToAccessTopLevelName *create(ConstraintSystem &cs, ConstraintLocator *locator); @@ -1825,11 +1825,11 @@ class AllowNonClassTypeToConvertToAnyObject final : public ContextualMismatch { ConstraintLocator *locator); public: - std::string getName() const { + std::string getName() const override { return "allow non-class type to convert to 'AnyObject'"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowNonClassTypeToConvertToAnyObject * create(ConstraintSystem &cs, Type type, ConstraintLocator *locator); @@ -1852,11 +1852,11 @@ class AllowCoercionToForceCast final : public ContextualMismatch { toType, locator, /*warning*/ true) {} public: - std::string getName() const { + std::string getName() const override { return "allow coercion to be treated as a force-cast"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static AllowCoercionToForceCast *create(ConstraintSystem &cs, Type fromType, Type toType, @@ -1894,11 +1894,11 @@ class SpecifyKeyPathRootType final : public ConstraintFix { : ConstraintFix(cs, FixKind::SpecifyKeyPathRootType, locator) {} public: - std::string getName() const { + std::string getName() const override { return "specify key path root type"; } - bool diagnose(const Solution &solution, bool asNote = false) const; + bool diagnose(const Solution &solution, bool asNote = false) const override; static SpecifyKeyPathRootType *create(ConstraintSystem &cs, ConstraintLocator *locator); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index da8d00a506a82..b0301f2fb8d76 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -962,12 +962,12 @@ namespace { public: StrangeInterpolationRewriter(ASTContext &Ctx) : Context(Ctx) {} - virtual bool walkToDeclPre(Decl *D) { + virtual bool walkToDeclPre(Decl *D) override { // We don't want to look inside decls. return false; } - virtual std::pair walkToExprPre(Expr *E) { + virtual std::pair walkToExprPre(Expr *E) override { // One InterpolatedStringLiteralExpr should never be nested inside // another except as a child of a CallExpr, and we don't recurse into // the children of CallExprs. diff --git a/lib/SymbolGraphGen/SymbolGraphASTWalker.h b/lib/SymbolGraphGen/SymbolGraphASTWalker.h index 9a1ebae5e4908..81c9db978468c 100644 --- a/lib/SymbolGraphGen/SymbolGraphASTWalker.h +++ b/lib/SymbolGraphGen/SymbolGraphASTWalker.h @@ -86,7 +86,7 @@ struct SymbolGraphASTWalker : public SourceEntityWalker { // MARK: - SourceEntityWalker - virtual bool walkToDeclPre(Decl *D, CharSourceRange Range); + virtual bool walkToDeclPre(Decl *D, CharSourceRange Range) override; }; } // end namespace symbolgraphgen diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index d9d437f234ff0..0c15c3da24e3e 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -317,13 +317,13 @@ class UnsupportedEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { return false; } bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { return false; } }; @@ -337,13 +337,13 @@ class EmptyEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { return false; } bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { return false; } }; @@ -361,14 +361,14 @@ class TrivialEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { *index = -1; return true; } bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { *CaseIndex = 0; return true; } @@ -389,7 +389,7 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *index) const { + int *index) const override { uint32_t tag = 0; if (!reader.readInteger(address, getSize(), &tag)) { return false; @@ -404,7 +404,7 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { uint32_t tag = 0; if (!reader.readInteger(address, getSize(), &tag)) { return false; @@ -433,7 +433,7 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { FieldInfo PayloadCase = getCases()[0]; if (getSize() < PayloadCase.TI.getSize()) { // Single payload enums that use a separate tag don't export any XIs @@ -464,7 +464,7 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { auto PayloadCase = getCases()[0]; auto PayloadSize = PayloadCase.TI.getSize(); auto DiscriminatorAddress = address + PayloadSize; @@ -550,7 +550,7 @@ class SimpleMultiPayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { unsigned long PayloadSize = getPayloadSize(); unsigned PayloadCount = getNumPayloadCases(); unsigned TagSize = getSize() - PayloadSize; @@ -573,7 +573,7 @@ class SimpleMultiPayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { unsigned long PayloadSize = getPayloadSize(); unsigned PayloadCount = getNumPayloadCases(); unsigned NumCases = getNumCases(); @@ -802,7 +802,7 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo { bool readExtraInhabitantIndex(remote::MemoryReader &reader, remote::RemoteAddress address, - int *extraInhabitantIndex) const { + int *extraInhabitantIndex) const override { unsigned long payloadSize = getPayloadSize(); // Multi payload enums that use spare bits export unused tag values as XIs. @@ -879,7 +879,7 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo { bool projectEnumValue(remote::MemoryReader &reader, remote::RemoteAddress address, - int *CaseIndex) const { + int *CaseIndex) const override { unsigned long payloadSize = getPayloadSize(); unsigned NumPayloadCases = getNumPayloadCases(); diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm index 61593760d31fd..821fecfb7fb0b 100644 --- a/stdlib/public/runtime/ReflectionMirror.mm +++ b/stdlib/public/runtime/ReflectionMirror.mm @@ -247,16 +247,16 @@ virtual const FieldType recursiveChildMetadata(intptr_t index, // Implementation for tuples. struct TupleImpl : ReflectionMirrorImpl { - char displayStyle() { + char displayStyle() override { return 't'; } - intptr_t count() { + intptr_t count() override { auto *Tuple = static_cast(type); return Tuple->NumElements; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { auto *Tuple = static_cast(type); if (i < 0 || (size_t)i > Tuple->NumElements) @@ -268,7 +268,7 @@ intptr_t childOffset(intptr_t i) { } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto *Tuple = static_cast(type); if (i < 0 || (size_t)i > Tuple->NumElements) @@ -306,7 +306,7 @@ const FieldType childMetadata(intptr_t i, const char **outName, } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto eltOffset = childOffset(i); auto fieldType = childMetadata(i, outName, outFreeFunc); @@ -437,11 +437,11 @@ bool isReflectable() { return Description->isReflectable(); } - char displayStyle() { + char displayStyle() override { return 's'; } - intptr_t count() { + intptr_t count() override { if (!isReflectable()) { return 0; } @@ -450,7 +450,7 @@ intptr_t count() { return Struct->getDescription()->NumFields; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { auto *Struct = static_cast(type); if (i < 0 || (size_t)i > Struct->getDescription()->NumFields) @@ -461,7 +461,7 @@ intptr_t childOffset(intptr_t i) { } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { StringRef name; FieldType fieldInfo; std::tie(name, fieldInfo) = getFieldAt(type, i); @@ -474,7 +474,7 @@ const FieldType childMetadata(intptr_t i, const char **outName, } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto fieldInfo = childMetadata(i, outName, outFreeFunc); auto *bytes = reinterpret_cast(value); @@ -516,11 +516,11 @@ bool isReflectable() { return name.data(); } - char displayStyle() { + char displayStyle() override { return 'e'; } - intptr_t count() { + intptr_t count() override { if (!isReflectable()) { return 0; } @@ -535,17 +535,17 @@ intptr_t count() { return (payloadType != nullptr) ? 1 : 0; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { return 0; } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { return FieldType(); } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { unsigned tag; const Metadata *payloadType; bool indirect; @@ -589,7 +589,7 @@ AnyReturn subscript(intptr_t i, const char **outName, return AnyReturn(result); } - const char *enumCaseName() { + const char *enumCaseName() override { if (!isReflectable()) { return nullptr; } @@ -607,7 +607,7 @@ bool isReflectable() { return Description->isReflectable(); } - char displayStyle() { + char displayStyle() override { return 'c'; } @@ -635,7 +635,7 @@ ClassImpl superclassMirror() { swift::crash("No superclass mirror found"); } - intptr_t count() { + intptr_t count() override { if (!isReflectable()) return 0; @@ -646,7 +646,7 @@ intptr_t count() { return count; } - intptr_t recursiveCount() { + intptr_t recursiveCount() override { if (hasSuperclassMirror()) { return superclassMirror().recursiveCount() + count(); } @@ -654,7 +654,7 @@ intptr_t recursiveCount() { return count(); } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { auto *Clas = static_cast(type); auto description = Clas->getDescription(); @@ -679,7 +679,7 @@ intptr_t childOffset(intptr_t i) { return (intptr_t)fieldOffset; } - intptr_t recursiveChildOffset(intptr_t i) { + intptr_t recursiveChildOffset(intptr_t i) override { if (hasSuperclassMirror()) { auto superMirror = superclassMirror(); auto superclassFieldCount = superMirror.recursiveCount(); @@ -695,7 +695,7 @@ intptr_t recursiveChildOffset(intptr_t i) { } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { StringRef name; FieldType fieldInfo; std::tie(name, fieldInfo) = getFieldAt(type, i); @@ -709,8 +709,7 @@ const FieldType childMetadata(intptr_t i, const char **outName, const FieldType recursiveChildMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) - { + void (**outFreeFunc)(const char *)) override { if (hasSuperclassMirror()) { auto superMirror = superclassMirror(); auto superclassFieldCount = superMirror.recursiveCount(); @@ -726,7 +725,7 @@ const FieldType recursiveChildMetadata(intptr_t i, } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { auto fieldInfo = childMetadata(i, outName, outFreeFunc); auto *bytes = *reinterpret_cast(value); @@ -794,25 +793,25 @@ virtual const FieldType recursiveChildMetadata(intptr_t index, // Implementation for metatypes. struct MetatypeImpl : ReflectionMirrorImpl { - char displayStyle() { + char displayStyle() override { return '\0'; } - intptr_t count() { + intptr_t count() override { return 0; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { swift::crash("Metatypes have no children."); } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Metatypes have no children."); } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Metatypes have no children."); } }; @@ -820,25 +819,25 @@ AnyReturn subscript(intptr_t i, const char **outName, // Implementation for opaque types. struct OpaqueImpl : ReflectionMirrorImpl { - char displayStyle() { + char displayStyle() override { return '\0'; } - intptr_t count() { + intptr_t count() override { return 0; } - intptr_t childOffset(intptr_t i) { + intptr_t childOffset(intptr_t i) override { swift::crash("Opaque types have no children."); } const FieldType childMetadata(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Opaque types have no children."); } AnyReturn subscript(intptr_t i, const char **outName, - void (**outFreeFunc)(const char *)) { + void (**outFreeFunc)(const char *)) override { swift::crash("Opaque types have no children."); } }; From 721f90356735672ca030d54a1d7f26eb0f46109d Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 12 Aug 2020 17:39:06 -0700 Subject: [PATCH 124/663] Address code-review feedback for #33430 --- include/swift/AST/ModuleDependencies.h | 2 +- include/swift/Frontend/ModuleInterfaceLoader.h | 11 ++++++++--- test/ScanDependencies/explicit-framework-irgen.swift | 6 +++--- test/ScanDependencies/module_framework.swift | 4 ++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 766e8840279e5..5eab3844b32d8 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -129,7 +129,7 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase { ArrayRef buildCommandLine, ArrayRef extraPCMArgs, StringRef contextHash, - bool isFramework = false + bool isFramework ) : ModuleDependenciesStorageBase(ModuleDependenciesKind::Swift, compiledModulePath), swiftInterfaceFile(swiftInterfaceFile), diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 84a23442e0ff2..9e60d92c080fa 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -112,7 +112,6 @@ #include "swift/Frontend/ModuleInterfaceSupport.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "llvm/Support/StringSaver.h" -#include namespace clang { class CompilerInstance; @@ -263,8 +262,14 @@ class ExplicitModuleMapParser { } else if (key == "sourceInfoPath") { result.moduleSourceInfoPath = val.str(); } else if (key == "isFramework") { - std::istringstream is(val.str()); - is >> std::boolalpha >> result.isFramework; + auto valStr = val.str(); + valStr.erase(std::remove(valStr.begin(), valStr.end(), '\n'), valStr.end()); + if (valStr.compare("true") == 0) + result.isFramework = true; + else if (valStr.compare("false") == 0) + result.isFramework = false; + else + llvm_unreachable("Unexpected JSON value for isFramework"); } else { // Being forgiving for future fields. continue; diff --git a/test/ScanDependencies/explicit-framework-irgen.swift b/test/ScanDependencies/explicit-framework-irgen.swift index 516b2a3f74855..0ad514de35a2b 100644 --- a/test/ScanDependencies/explicit-framework-irgen.swift +++ b/test/ScanDependencies/explicit-framework-irgen.swift @@ -27,11 +27,11 @@ import Foo // This test is to verify autolinking behavior so it is macOS-specific. -// REQUIRES OS=macosx +// REQUIRES: OS=macosx // RUN: otool -l %t/explicit-framework-irgen.o | %FileCheck %s // CHECK: cmd LC_LINKER_OPTION -// CHECK-NEXT: cmdsize 32 -// CHECK-NEXT: count 2 +// CHECK-NEXT: cmdsize +// CHECK-NEXT: count // CHECK-NEXT: string #1 -framework // CHECK-NEXT: string #2 Foo diff --git a/test/ScanDependencies/module_framework.swift b/test/ScanDependencies/module_framework.swift index a6b0dfdeaa291..937667d98d025 100644 --- a/test/ScanDependencies/module_framework.swift +++ b/test/ScanDependencies/module_framework.swift @@ -3,8 +3,8 @@ // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json -// REQUIRES: objc_interop - +// REQUIRES: OS=macosx + import CryptoKit // CHECK: "mainModuleName": "deps" From 5f74fe31c62b3603338f45b245c4b63dda3c0db0 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Thu, 13 Aug 2020 22:36:04 +0200 Subject: [PATCH 125/663] [Localization] Modify messages' format in yaml --- localization/diagnostics/en.yaml | 9228 +++++++++--------------------- 1 file changed, 2837 insertions(+), 6391 deletions(-) diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index f61d7cdcbbfba..b4dfdad00c661 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -13,11821 +13,8267 @@ # This file defines the diagnostic messages for the English language. # Each diagnostic is described in the following format: # - id: -# msg: >- -# +# msg: "" +# +# The diagnostic message should be in double quotes and in one line, that +# means we will break the 80 characters line limit rule. That's mainly +# because currently `llvm::YAMLParser` doesn't support literal string +# folding, therefore we can't use YAML block scalars i.e. `>-`. # #===----------------------------------------------------------------------===# - id: invalid_diagnostic - msg: >- - INTERNAL ERROR: this diagnostic should not be produced + msg: "INTERNAL ERROR: this diagnostic should not be produced" - id: not_implemented - msg: >- - INTERNAL ERROR: feature not implemented: %0 + msg: "INTERNAL ERROR: feature not implemented: %0" - id: error_opening_output - msg: >- - error opening '%0' for output: %1 + msg: "error opening '%0' for output: %1" - id: cannot_find_group_info_file - msg: >- - cannot find group info file at path: '%0' + msg: "cannot find group info file at path: '%0'" - id: cannot_parse_group_info_file - msg: >- - cannot parse group info file at path: '%0' + msg: "cannot parse group info file at path: '%0'" - id: error_no_group_info - msg: >- - no group info found for file: '%0' + msg: "no group info found for file: '%0'" - id: previous_decldef - msg: >- - previous definition of %0 is here + msg: "previous definition of %0 is here" - id: brace_stmt_suggest_do - msg: >- - did you mean to use a 'do' statement? + msg: "did you mean to use a 'do' statement?" - id: while_parsing_as_left_angle_bracket - msg: >- - while parsing this '<' as a type parameter bracket + msg: "while parsing this '<' as a type parameter bracket" - id: remark_max_determinism_overriding - msg: >- - SWIFTC_MAXIMUM_DETERMINISM overriding %0 + msg: "SWIFTC_MAXIMUM_DETERMINISM overriding %0" - id: super_not_in_class_method - msg: >- - 'super' cannot be used outside of class members + msg: "'super' cannot be used outside of class members" - id: class_func_not_in_class - msg: >- - class methods are only allowed within classes; use 'static' to declare a - %select{static|requirement fulfilled by either a static or class}0 method + msg: "class methods are only allowed within classes; use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 method" - id: class_var_not_in_class - msg: >- - class properties are only allowed within classes; use 'static' to declare - a %select{static|requirement fulfilled by either a static or class}0 - property + msg: "class properties are only allowed within classes; use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 property" - id: class_subscript_not_in_class - msg: >- - class subscripts are only allowed within classes; use 'static' to declare - a %select{static|requirement fulfilled by either a static or class}0 - subscript + msg: "class subscripts are only allowed within classes; use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 subscript" - id: func_decl_without_brace - msg: >- - expected '{' in body of function declaration + msg: "expected '{' in body of function declaration" - id: convert_let_to_var - msg: >- - change 'let' to 'var' to make it mutable + msg: "change 'let' to 'var' to make it mutable" - id: note_typo_candidate - msg: >- - did you mean '%0'? + msg: "did you mean '%0'?" - id: profile_read_error - msg: >- - failed to load profile data '%0': '%1' + msg: "failed to load profile data '%0': '%1'" - id: protocol_extension_redundant_requirement - msg: >- - requirement of '%1' to '%2' is redundant in an extension of '%0' + msg: "requirement of '%1' to '%2' is redundant in an extension of '%0'" - id: attr_only_on_parameters - msg: >- - '%0' may only be used on parameters + msg: "'%0' may only be used on parameters" - id: function_type_no_parens - msg: >- - single argument function types require parentheses + msg: "single argument function types require parentheses" - id: error_underlying_module_not_found - msg: >- - underlying Objective-C module %0 not found + msg: "underlying Objective-C module %0 not found" - id: generic_signature_not_minimal - msg: >- - generic requirement '%0' is redundant in %1 + msg: "generic requirement '%0' is redundant in %1" - id: generic_signature_not_valid - msg: >- - generic signature %0 is invalid + msg: "generic signature %0 is invalid" - id: generic_signature_not_equal - msg: >- - generic signature %0 is not equal to new signature %1 + msg: "generic signature %0 is not equal to new signature %1" - id: sdk_node_unrecognized_key - msg: >- - unrecognized key '%0' in SDK node + msg: "unrecognized key '%0' in SDK node" - id: sdk_node_unrecognized_node_kind - msg: >- - unrecognized SDK node kind '%0' + msg: "unrecognized SDK node kind '%0'" - id: sdk_node_unrecognized_type_attr_kind - msg: >- - unrecognized type attribute '%0' in SDK node + msg: "unrecognized type attribute '%0' in SDK node" - id: sdk_node_unrecognized_decl_attr_kind - msg: >- - unrecognized declaration attribute '%0' in SDK node + msg: "unrecognized declaration attribute '%0' in SDK node" - id: sdk_node_unrecognized_decl_kind - msg: >- - unrecognized declaration kind '%0' in SDK node + msg: "unrecognized declaration kind '%0' in SDK node" - id: sdk_node_unrecognized_accessor_kind - msg: >- - unrecognized accessor kind '%0' in SDK node + msg: "unrecognized accessor kind '%0' in SDK node" - id: source_location_creates_file_id_conflicts - msg: >- - '#sourceLocation' directive produces '#fileID' string of '%0', which - conflicts with '#fileID' strings produced by other paths in the module + msg: "'#sourceLocation' directive produces '#fileID' string of '%0', which conflicts with '#fileID' strings produced by other paths in the module" - id: fixit_correct_source_location_file - msg: >- - change file in '#sourceLocation' to '%0' + msg: "change file in '#sourceLocation' to '%0'" + +- id: error_two_files_same_name + msg: "filename \"%0\" used twice: '%1' and '%2'" + +- id: note_explain_two_files_same_name + msg: "filenames are used to distinguish private declarations with the same name" - id: circular_reference - msg: >- - circular reference + msg: "circular reference" - id: circular_reference_through - msg: >- - through reference here + msg: "through reference here" - id: circular_class_inheritance - msg: >- - %0 inherits from itself + msg: "%0 inherits from itself" - id: circular_enum_inheritance - msg: >- - %0 has a raw type that depends on itself + msg: "%0 has a raw type that depends on itself" - id: circular_protocol_def - msg: >- - protocol %0 refines itself + msg: "protocol %0 refines itself" - id: kind_declname_declared_here - msg: >- - %0 %1 declared here + msg: "%0 %1 declared here" - id: warn_property_wrapper_module_scope - msg: >- - ignoring associated type %0 in favor of module-scoped property wrapper - %0; please qualify the reference with %1 + msg: "ignoring associated type %0 in favor of module-scoped property wrapper %0; please qualify the reference with %1" - id: circular_type_resolution_note - msg: >- - while resolving type %0 + msg: "while resolving type %0" - id: cannot_load_swiftoverlay_file - msg: >- - cannot load cross-import overlay for '%0' and '%1': %2 (declared by '%3') + msg: "cannot load cross-import overlay for '%0' and '%1': %2 (declared by '%3')" - id: cannot_list_swiftcrossimport_dir - msg: >- - cannot list cross-import overlays for '%0': %1 (declared in '%2') + msg: "cannot list cross-import overlays for '%0': %1 (declared in '%2')" - id: cross_imported_by_both_modules - msg: >- - modules %0 and %1 both declare module %2 as a cross-import overlay, which - may cause paradoxical behavior when looking up names in them; please report this - bug to the maintainers of these modules + msg: "modules %0 and %1 both declare module %2 as a cross-import overlay, which may cause paradoxical behavior when looking up names in them; please report this bug to the maintainers of these modules" + +- id: scanner_find_cycle + msg: "dependency scanner detected dependency cycle: '%0'" - id: opening_brace - msg: >- - to match this opening '{' + msg: "to match this opening '{'" - id: opening_bracket - msg: >- - to match this opening '[' + msg: "to match this opening '['" - id: opening_paren - msg: >- - to match this opening '(' + msg: "to match this opening '('" - id: opening_angle - msg: >- - to match this opening '<' + msg: "to match this opening '<'" - id: extra_rbrace - msg: >- - extraneous '}' at top level + msg: "extraneous '}' at top level" - id: structure_overflow - msg: >- - structure nesting level exceeded maximum of %0 + msg: "structure nesting level exceeded maximum of %0" - id: expected_close_to_if_directive - msg: >- - expected #else or #endif at end of conditional compilation block + msg: "expected #else or #endif at end of conditional compilation block" - id: expected_close_after_else_directive - msg: >- - further conditions after #else are unreachable + msg: "further conditions after #else are unreachable" - id: unexpected_conditional_compilation_block_terminator - msg: >- - unexpected conditional compilation block terminator + msg: "unexpected conditional compilation block terminator" - id: incomplete_conditional_compilation_directive - msg: >- - incomplete condition in conditional compilation directive + msg: "incomplete condition in conditional compilation directive" - id: extra_tokens_conditional_compilation_directive - msg: >- - extra tokens following conditional compilation directive + msg: "extra tokens following conditional compilation directive" - id: unexpected_rbrace_in_conditional_compilation_block - msg: >- - unexpected '}' in conditional compilation block + msg: "unexpected '}' in conditional compilation block" - id: unexpected_if_following_else_compilation_directive - msg: >- - unexpected 'if' keyword following '#else' conditional compilation - directive; did you mean '#elseif'? + msg: "unexpected 'if' keyword following '#else' conditional compilation directive; did you mean '#elseif'?" - id: pound_diagnostic_expected_string - msg: >- - expected string literal in %select{#warning|#error}0 directive + msg: "expected string literal in %select{#warning|#error}0 directive" - id: pound_diagnostic_expected - msg: >- - expected '%0' in %select{#warning|#error}1 directive + msg: "expected '%0' in %select{#warning|#error}1 directive" - id: pound_diagnostic_expected_parens - msg: >- - %select{#warning|#error}0 directive requires parentheses + msg: "%select{#warning|#error}0 directive requires parentheses" - id: pound_diagnostic_interpolation - msg: >- - string interpolation is not allowed in %select{#warning|#error}0 - directives + msg: "string interpolation is not allowed in %select{#warning|#error}0 directives" - id: extra_tokens_pound_diagnostic_directive - msg: >- - extra tokens following %select{#warning|#error}0 directive + msg: "extra tokens following %select{#warning|#error}0 directive" - id: sourceLocation_expected - msg: >- - expected '%0' in #sourceLocation directive + msg: "expected '%0' in #sourceLocation directive" - id: unexpected_line_directive - msg: >- - parameterless closing #sourceLocation() directive without prior opening - #sourceLocation(file:,line:) directive + msg: "parameterless closing #sourceLocation() directive without prior opening #sourceLocation(file:,line:) directive" - id: expected_line_directive_number - msg: >- - expected starting line number for #sourceLocation directive + msg: "expected starting line number for #sourceLocation directive" - id: expected_line_directive_name - msg: >- - expected filename string literal for #sourceLocation directive + msg: "expected filename string literal for #sourceLocation directive" - id: extra_tokens_line_directive - msg: >- - extra tokens at the end of #sourceLocation directive + msg: "extra tokens at the end of #sourceLocation directive" - id: line_directive_line_zero - msg: >- - the line number needs to be greater than zero + msg: "the line number needs to be greater than zero" - id: escaped_parameter_name - msg: >- - keyword '%0' does not need to be escaped in argument list + msg: "keyword '%0' does not need to be escaped in argument list" - id: forbidden_interpolated_string - msg: >- - %0 cannot be an interpolated string literal + msg: "%0 cannot be an interpolated string literal" - id: forbidden_extended_escaping_string - msg: >- - %0 cannot be an extended escaping string literal + msg: "%0 cannot be an extended escaping string literal" - id: lex_nul_character - msg: >- - nul character embedded in middle of file + msg: "nul character embedded in middle of file" - id: lex_utf16_bom_marker - msg: >- - input files must be encoded as UTF-8 instead of UTF-16 + msg: "input files must be encoded as UTF-8 instead of UTF-16" - id: lex_hashbang_not_allowed - msg: >- - hashbang line is allowed only in the main file + msg: "hashbang line is allowed only in the main file" - id: lex_unprintable_ascii_character - msg: >- - unprintable ASCII character found in source file + msg: "unprintable ASCII character found in source file" - id: lex_invalid_utf8 - msg: >- - invalid UTF-8 found in source file + msg: "invalid UTF-8 found in source file" - id: lex_single_quote_string - msg: >- - single-quoted string literal found, use '"' + msg: "single-quoted string literal found, use '\"'" - id: lex_invalid_curly_quote - msg: >- - unicode curly quote found, replace with '"' + msg: "unicode curly quote found, replace with '\"'" - id: lex_confusable_character - msg: >- - unicode character '%0' (%1) looks similar to '%2' (%3); did you mean to use '%2' (%3)? + msg: "unicode character '%0' (%1) looks similar to '%2' (%3); did you mean to use '%2' (%3)?" - id: lex_nonbreaking_space - msg: >- - non-breaking space (U+00A0) used instead of regular space + msg: "non-breaking space (U+00A0) used instead of regular space" - id: lex_unterminated_block_comment - msg: >- - unterminated '/*' comment + msg: "unterminated '/*' comment" - id: lex_comment_start - msg: >- - comment started here + msg: "comment started here" - id: lex_unterminated_string - msg: >- - unterminated string literal + msg: "unterminated string literal" - id: lex_invalid_escape - msg: >- - invalid escape sequence in literal + msg: "invalid escape sequence in literal" - id: lex_invalid_u_escape - msg: >- - \u{...} escape sequence expects between 1 and 8 hex digits + msg: "\\u{...} escape sequence expects between 1 and 8 hex digits" - id: lex_invalid_u_escape_rbrace - msg: >- - expected '}' in \u{...} escape sequence + msg: "expected '}' in \\u{...} escape sequence" - id: lex_invalid_escape_delimiter - msg: >- - too many '#' characters in delimited escape + msg: "too many '#' characters in delimited escape" - id: lex_invalid_closing_delimiter - msg: >- - too many '#' characters in closing delimiter + msg: "too many '#' characters in closing delimiter" - id: lex_invalid_unicode_scalar - msg: >- - invalid unicode scalar + msg: "invalid unicode scalar" - id: lex_unicode_escape_braces - msg: >- - expected hexadecimal code in braces after unicode escape + msg: "expected hexadecimal code in braces after unicode escape" - id: lex_illegal_multiline_string_start - msg: >- - multi-line string literal content must begin on a new line + msg: "multi-line string literal content must begin on a new line" - id: lex_illegal_multiline_string_end - msg: >- - multi-line string literal closing delimiter must begin on a new line + msg: "multi-line string literal closing delimiter must begin on a new line" - id: lex_multiline_string_indent_inconsistent - msg: >- - %select{unexpected space in|unexpected tab in|insufficient}2 indentation - of %select{line|next %1 lines}0 in multi-line string literal + msg: "%select{unexpected space in|unexpected tab in|insufficient}2 indentation of %select{line|next %1 lines}0 in multi-line string literal" - id: lex_multiline_string_indent_should_match_here - msg: >- - should match %select{space|tab}0 here + msg: "should match %select{space|tab}0 here" - id: lex_multiline_string_indent_change_line - msg: >- - change indentation of %select{this line|these lines}0 to match closing - delimiter + msg: "change indentation of %select{this line|these lines}0 to match closing delimiter" - id: lex_escaped_newline_at_lastline - msg: >- - escaped newline at the last line is not allowed + msg: "escaped newline at the last line is not allowed" - id: lex_invalid_character - msg: >- - invalid character in source file + msg: "invalid character in source file" - id: lex_invalid_identifier_start_character - msg: >- - an identifier cannot begin with this character + msg: "an identifier cannot begin with this character" - id: lex_expected_digit_in_fp_exponent - msg: >- - expected a digit in floating point exponent + msg: "expected a digit in floating point exponent" - id: lex_invalid_digit_in_fp_exponent - msg: >- - '%0' is not a valid %select{digit|first character}1 in floating point - exponent + msg: "'%0' is not a valid %select{digit|first character}1 in floating point exponent" - id: lex_invalid_digit_in_int_literal - msg: >- - '%0' is not a valid %select{binary digit (0 or 1)|octal digit - (0-7)|digit|hexadecimal digit (0-9, A-F)}1 in integer literal + msg: "'%0' is not a valid %select{binary digit (0 or 1)|octal digit (0-7)|digit|hexadecimal digit (0-9, A-F)}1 in integer literal" - id: lex_expected_binary_exponent_in_hex_float_literal - msg: >- - hexadecimal floating point literal must end with an exponent + msg: "hexadecimal floating point literal must end with an exponent" - id: lex_unexpected_block_comment_end - msg: >- - unexpected end of block comment + msg: "unexpected end of block comment" - id: lex_unary_equal - msg: >- - '=' must have consistent whitespace on both sides + msg: "'=' must have consistent whitespace on both sides" - id: extra_whitespace_period - msg: >- - extraneous whitespace after '.' is not permitted + msg: "extraneous whitespace after '.' is not permitted" - id: lex_editor_placeholder - msg: >- - editor placeholder in source file + msg: "editor placeholder in source file" - id: lex_editor_placeholder_in_playground - msg: >- - editor placeholder in source file + msg: "editor placeholder in source file" - id: lex_conflict_marker_in_file - msg: >- - source control conflict marker in source file + msg: "source control conflict marker in source file" - id: note_in_decl_extension - msg: >- - in %select{declaration|extension}0 of %1 + msg: "in %select{declaration|extension}0 of %1" - id: line_directive_style_deprecated - msg: >- - #line directive was renamed to #sourceLocation + msg: "#line directive was renamed to #sourceLocation" - id: declaration_same_line_without_semi - msg: >- - consecutive declarations on a line must be separated by ';' + msg: "consecutive declarations on a line must be separated by ';'" - id: expected_decl - msg: >- - expected declaration + msg: "expected declaration" - id: expected_identifier_in_decl - msg: >- - expected identifier in %0 declaration + msg: "expected identifier in %0 declaration" - id: expected_keyword_in_decl - msg: >- - expected '%0' keyword in %1 declaration + msg: "expected '%0' keyword in %1 declaration" - id: number_cant_start_decl_name - msg: >- - %0 name can only start with a letter or underscore, not a number + msg: "%0 name can only start with a letter or underscore, not a number" - id: expected_identifier_after_case_comma - msg: >- - expected identifier after comma in enum 'case' declaration + msg: "expected identifier after comma in enum 'case' declaration" - id: decl_redefinition - msg: >- - definition conflicts with previous value + msg: "definition conflicts with previous value" - id: let_cannot_be_computed_property - msg: >- - 'let' declarations cannot be computed properties + msg: "'let' declarations cannot be computed properties" - id: let_cannot_be_observing_property - msg: >- - 'let' declarations cannot be observing properties + msg: "'let' declarations cannot be observing properties" - id: let_cannot_be_addressed_property - msg: >- - 'let' declarations cannot have addressors + msg: "'let' declarations cannot have addressors" - id: disallowed_var_multiple_getset - msg: >- - 'var' declarations with multiple variables cannot have explicit - getters/setters + msg: "'var' declarations with multiple variables cannot have explicit getters/setters" - id: disallowed_init - msg: >- - initial value is not allowed here + msg: "initial value is not allowed here" - id: var_init_self_referential - msg: >- - variable used within its own initial value + msg: "variable used within its own initial value" - id: disallowed_enum_element - msg: >- - enum 'case' is not allowed outside of an enum + msg: "enum 'case' is not allowed outside of an enum" - id: decl_inner_scope - msg: >- - declaration is only valid at file scope + msg: "declaration is only valid at file scope" - id: decl_not_static - msg: >- - declaration cannot be marked %0 + msg: "declaration cannot be marked %0" - id: cskeyword_not_attribute - msg: >- - '%0' is a declaration modifier, not an attribute + msg: "'%0' is a declaration modifier, not an attribute" - id: decl_already_static - msg: >- - %0 cannot appear after another 'static' or 'class' keyword + msg: "%0 cannot appear after another 'static' or 'class' keyword" - id: enum_case_dot_prefix - msg: >- - extraneous '.' in enum 'case' declaration + msg: "extraneous '.' in enum 'case' declaration" - id: static_var_decl_global_scope - msg: >- - %select{%error|static properties|class properties}0 may only be declared - on a type + msg: "%select{%error|static properties|class properties}0 may only be declared on a type" - id: computed_property_no_accessors - msg: >- - %select{computed property|subscript}0 must have accessors specified + msg: "%select{computed property|subscript}0 must have accessors specified" - id: expected_getset_in_protocol - msg: >- - expected get or set in a protocol property + msg: "expected get or set in a protocol property" - id: computed_property_missing_type - msg: >- - computed property must have an explicit type + msg: "computed property must have an explicit type" - id: getset_nontrivial_pattern - msg: >- - getter/setter can only be defined for a single variable + msg: "getter/setter can only be defined for a single variable" - id: expected_rbrace_in_getset - msg: >- - expected '}' at end of variable get/set clause + msg: "expected '}' at end of variable get/set clause" - id: duplicate_accessor - msg: >- - %select{variable|subscript}0 already has %1 + msg: "%select{variable|subscript}0 already has %1" - id: conflicting_accessor - msg: >- - %select{variable|subscript}0 cannot provide both %1 and %2 + msg: "%select{variable|subscript}0 cannot provide both %1 and %2" - id: previous_accessor - msg: >- - %select{|previous definition of }1%0 %select{defined |}1here + msg: "%select{|previous definition of }1%0 %select{defined |}1here" - id: expected_accessor_parameter_name - msg: >- - expected %select{setter|willSet|didSet}0 parameter name + msg: "expected %select{setter|willSet|didSet}0 parameter name" - id: expected_rparen_set_name - msg: >- - expected ')' after setter parameter name + msg: "expected ')' after setter parameter name" - id: expected_rparen_willSet_name - msg: >- - expected ')' after willSet parameter name + msg: "expected ')' after willSet parameter name" - id: expected_rparen_didSet_name - msg: >- - expected ')' after didSet parameter name + msg: "expected ')' after didSet parameter name" - id: expected_lbrace_accessor - msg: >- - expected '{' to start %0 definition + msg: "expected '{' to start %0 definition" - id: expected_accessor_kw - msg: >- - expected 'get', 'set', 'willSet', or 'didSet' keyword to start an - accessor definition + msg: "expected 'get', 'set', 'willSet', or 'didSet' keyword to start an accessor definition" - id: missing_getter - msg: >- - %select{variable|subscript}0 with %1 must also have a getter + msg: "%select{variable|subscript}0 with %1 must also have a getter" - id: missing_reading_accessor - msg: >- - %select{variable|subscript}0 with %1 must also have a getter, addressor, - or 'read' accessor + msg: "%select{variable|subscript}0 with %1 must also have a getter, addressor, or 'read' accessor" - id: observing_accessor_conflicts_with_accessor - msg: >- - %select{'willSet'|'didSet'}0 cannot be provided together with %1 + msg: "%select{'willSet'|'didSet'}0 cannot be provided together with %1" - id: observing_accessor_in_subscript - msg: >- - %select{'willSet'|'didSet'}0 is not allowed in subscripts + msg: "%select{'willSet'|'didSet'}0 is not allowed in subscripts" - id: getset_cannot_be_implied - msg: >- - variable with implied type cannot have implied getter/setter + msg: "variable with implied type cannot have implied getter/setter" - id: decl_expected_module_name - msg: >- - expected module name in import declaration + msg: "expected module name in import declaration" - id: expected_lbrace_extension - msg: >- - expected '{' in extension + msg: "expected '{' in extension" - id: expected_rbrace_extension - msg: >- - expected '}' at end of extension + msg: "expected '}' at end of extension" - id: extension_type_expected - msg: >- - expected type name in extension declaration + msg: "expected type name in extension declaration" - id: expected_equal_in_typealias - msg: >- - expected '=' in type alias declaration + msg: "expected '=' in type alias declaration" - id: expected_type_in_typealias - msg: >- - expected type in type alias declaration + msg: "expected type in type alias declaration" - id: expected_type_in_associatedtype - msg: >- - expected type in associated type declaration + msg: "expected type in associated type declaration" - id: associated_type_generic_parameter_list - msg: >- - associated types must not have a generic parameter list + msg: "associated types must not have a generic parameter list" - id: func_decl_without_paren - msg: >- - expected '(' in argument list of function declaration + msg: "expected '(' in argument list of function declaration" - id: static_func_decl_global_scope - msg: >- - %select{%error|static methods|class methods}0 may only be declared on a - type + msg: "%select{%error|static methods|class methods}0 may only be declared on a type" - id: func_decl_expected_arrow - msg: >- - expected '->' after function parameter tuple + msg: "expected '->' after function parameter tuple" - id: operator_static_in_protocol - msg: >- - operator '%0' declared in protocol must be 'static' + msg: "operator '%0' declared in protocol must be 'static'" - id: expected_lbrace_enum - msg: >- - expected '{' in enum + msg: "expected '{' in enum" - id: expected_rbrace_enum - msg: >- - expected '}' at end of enum + msg: "expected '}' at end of enum" - id: expected_lbrace_struct - msg: >- - expected '{' in struct + msg: "expected '{' in struct" - id: expected_rbrace_struct - msg: >- - expected '}' in struct + msg: "expected '}' in struct" - id: expected_lbrace_class - msg: >- - expected '{' in class + msg: "expected '{' in class" - id: expected_rbrace_class - msg: >- - expected '}' in class + msg: "expected '}' in class" - id: expected_colon_class - msg: >- - expected ':' to begin inheritance clause + msg: "expected ':' to begin inheritance clause" - id: generic_arguments_protocol - msg: >- - protocols do not allow generic parameters; use associated types instead + msg: "protocols do not allow generic parameters; use associated types instead" - id: expected_lbrace_protocol - msg: >- - expected '{' in protocol type + msg: "expected '{' in protocol type" - id: expected_rbrace_protocol - msg: >- - expected '}' in protocol + msg: "expected '}' in protocol" - id: protocol_setter_name - msg: >- - setter in a protocol cannot have a name + msg: "setter in a protocol cannot have a name" - id: protocol_method_with_body - msg: >- - protocol methods must not have bodies + msg: "protocol methods must not have bodies" - id: protocol_init_with_body - msg: >- - protocol initializers must not have bodies + msg: "protocol initializers must not have bodies" - id: subscript_decl_wrong_scope - msg: >- - 'subscript' functions may only be declared within a type + msg: "'subscript' functions may only be declared within a type" - id: expected_lparen_subscript - msg: >- - expected '(' for subscript parameters + msg: "expected '(' for subscript parameters" - id: subscript_has_name - msg: >- - subscripts cannot have a name + msg: "subscripts cannot have a name" - id: expected_arrow_subscript - msg: >- - expected '->' for subscript element type + msg: "expected '->' for subscript element type" - id: expected_type_subscript - msg: >- - expected subscripting element type + msg: "expected subscripting element type" - id: expected_lbrace_subscript - msg: >- - expected '{' in subscript to specify getter and setter implementation + msg: "expected '{' in subscript to specify getter and setter implementation" - id: expected_lbrace_subscript_protocol - msg: >- - subscript in protocol must have explicit { get } or { get set } specifier + msg: "subscript in protocol must have explicit { get } or { get set } specifier" - id: subscript_without_get - msg: >- - subscript declarations must have a getter + msg: "subscript declarations must have a getter" - id: invalid_nested_init - msg: >- - missing '%select{super.|self.}0' at initializer invocation + msg: "missing '%select{super.|self.}0' at initializer invocation" - id: initializer_decl_wrong_scope - msg: >- - initializers may only be declared within a type + msg: "initializers may only be declared within a type" - id: expected_lparen_initializer - msg: >- - expected '(' for initializer parameters + msg: "expected '(' for initializer parameters" - id: initializer_has_name - msg: >- - initializers cannot have a name + msg: "initializers cannot have a name" - id: destructor_decl_outside_class - msg: >- - deinitializers may only be declared within a class + msg: "deinitializers may only be declared within a class" - id: expected_lbrace_destructor - msg: >- - expected '{' for deinitializer + msg: "expected '{' for deinitializer" - id: destructor_has_name - msg: >- - deinitializers cannot have a name + msg: "deinitializers cannot have a name" - id: opened_destructor_expected_rparen - msg: >- - expected ')' to close parameter list + msg: "expected ')' to close parameter list" - id: destructor_params - msg: >- - no parameter clause allowed on deinitializer + msg: "no parameter clause allowed on deinitializer" - id: operator_decl_inner_scope - msg: >- - 'operator' may only be declared at file scope + msg: "'operator' may only be declared at file scope" - id: expected_operator_name_after_operator - msg: >- - expected operator name in operator declaration + msg: "expected operator name in operator declaration" - id: identifier_within_operator_name - msg: >- - '%0' is considered an identifier and must not appear within an operator - name + msg: "'%0' is considered an identifier and must not appear within an operator name" - id: operator_name_invalid_char - msg: >- - '%0' is not allowed in operator names + msg: "'%0' is not allowed in operator names" - id: postfix_operator_name_cannot_start_with_unwrap - msg: >- - postfix operator names starting with '?' or '!' are disallowed to avoid - collisions with built-in unwrapping operators + msg: "postfix operator names starting with '?' or '!' are disallowed to avoid collisions with built-in unwrapping operators" - id: deprecated_operator_body - msg: >- - operator should no longer be declared with body + msg: "operator should no longer be declared with body" - id: deprecated_operator_body_use_group - msg: >- - operator should no longer be declared with body; use a precedence group - instead + msg: "operator should no longer be declared with body; use a precedence group instead" - id: operator_decl_no_fixity - msg: >- - operator must be declared as 'prefix', 'postfix', or 'infix' + msg: "operator must be declared as 'prefix', 'postfix', or 'infix'" - id: operator_decl_expected_type - msg: >- - expected designated type in operator declaration + msg: "expected designated type in operator declaration" - id: operator_decl_trailing_comma - msg: >- - trailing comma in operator declaration + msg: "trailing comma in operator declaration" - id: precedencegroup_not_infix - msg: >- - only infix operators may declare a precedence + msg: "only infix operators may declare a precedence" - id: expected_precedencegroup_name - msg: >- - expected identifier after 'precedencegroup' + msg: "expected identifier after 'precedencegroup'" - id: expected_precedencegroup_lbrace - msg: >- - expected '{' after name of precedence group + msg: "expected '{' after name of precedence group" - id: expected_precedencegroup_attribute - msg: >- - expected operator attribute identifier in precedence group body + msg: "expected operator attribute identifier in precedence group body" - id: unknown_precedencegroup_attribute - msg: >- - '%0' is not a valid precedence group attribute + msg: "'%0' is not a valid precedence group attribute" - id: expected_precedencegroup_attribute_colon - msg: >- - expected colon after attribute name in precedence group + msg: "expected colon after attribute name in precedence group" - id: precedencegroup_attribute_redeclared - msg: >- - '%0' attribute for precedence group declared multiple times + msg: "'%0' attribute for precedence group declared multiple times" - id: expected_precedencegroup_associativity - msg: >- - expected 'none', 'left', or 'right' after 'associativity' + msg: "expected 'none', 'left', or 'right' after 'associativity'" - id: expected_precedencegroup_assignment - msg: >- - expected 'true' or 'false' after 'assignment' + msg: "expected 'true' or 'false' after 'assignment'" - id: expected_precedencegroup_relation - msg: >- - expected name of related precedence group after '%0' + msg: "expected name of related precedence group after '%0'" - id: expected_sil_keyword - msg: >- - expected SIL keyword + msg: "expected SIL keyword" - id: inout_not_attribute - msg: >- - @inout is no longer an attribute + msg: "@inout is no longer an attribute" - id: only_allowed_in_sil - msg: >- - '%0' only allowed in SIL modules + msg: "'%0' only allowed in SIL modules" - id: expected_sil_type - msg: >- - expected type in SIL code + msg: "expected type in SIL code" - id: expected_sil_colon_value_ref - msg: >- - expected ':' before type in SIL value reference + msg: "expected ':' before type in SIL value reference" - id: expected_sil_value_name - msg: >- - expected SIL value name + msg: "expected SIL value name" - id: expected_sil_type_kind - msg: >- - expected SIL type to %0 + msg: "expected SIL type to %0" - id: expected_sil_constant - msg: >- - expected constant in SIL code + msg: "expected constant in SIL code" - id: referenced_value_no_accessor - msg: >- - referenced declaration has no %select{getter|setter}0 + msg: "referenced declaration has no %select{getter|setter}0" - id: expected_sil_value_ownership_kind - msg: >- - expected value ownership kind in SIL code + msg: "expected value ownership kind in SIL code" - id: silfunc_and_silarg_have_incompatible_sil_value_ownership - msg: >- - SILFunction and SILArgument have mismatching ValueOwnershipKinds. - Function type specifies: '@%0'. SIL argument specifies: '@%1'. + msg: "SILFunction and SILArgument have mismatching ValueOwnershipKinds. Function type specifies: '@%0'. SIL argument specifies: '@%1'." - id: expected_sil_colon - msg: >- - expected ':' before %0 + msg: "expected ':' before %0" - id: expected_sil_tuple_index - msg: >- - expected tuple element index + msg: "expected tuple element index" - id: invalid_index_subset - msg: >- - invalid index subset; expected '[SU]+' where 'S' represents set indices - and 'U' represents unset indices + msg: "invalid index subset; expected '[SU]+' where 'S' represents set indices and 'U' represents unset indices" - id: sil_value_redefinition - msg: >- - redefinition of value '%0' + msg: "redefinition of value '%0'" - id: sil_value_use_type_mismatch - msg: >- - value '%0' defined with mismatching type %1 (expected %2) + msg: "value '%0' defined with mismatching type %1 (expected %2)" - id: sil_value_def_type_mismatch - msg: >- - value '%0' used with mismatching type %1 (expected %2) + msg: "value '%0' used with mismatching type %1 (expected %2)" - id: sil_use_of_undefined_value - msg: >- - use of undefined value '%0' + msg: "use of undefined value '%0'" - id: sil_prior_reference - msg: >- - prior reference was here + msg: "prior reference was here" - id: expected_colon_in_sil_location - msg: >- - expected ':' in SIL location + msg: "expected ':' in SIL location" - id: sil_invalid_line_in_sil_location - msg: >- - line number must be a positive integer + msg: "line number must be a positive integer" - id: sil_invalid_column_in_sil_location - msg: >- - column number must be a positive integer + msg: "column number must be a positive integer" - id: sil_invalid_scope_slot - msg: >- - scope number must be a positive integer + msg: "scope number must be a positive integer " - id: sil_scope_undeclared - msg: >- - scope number %0 needs to be declared before first use + msg: "scope number %0 needs to be declared before first use" - id: sil_scope_redefined - msg: >- - scope number %0 is already defined + msg: "scope number %0 is already defined" - id: expected_sil_instr_start_of_line - msg: >- - SIL instructions must be at the start of a line + msg: "SIL instructions must be at the start of a line" - id: expected_equal_in_sil_instr - msg: >- - expected '=' in SIL instruction + msg: "expected '=' in SIL instruction" - id: wrong_result_count_in_sil_instr - msg: >- - wrong number of results for SIL instruction, expected %0 + msg: "wrong number of results for SIL instruction, expected %0" - id: expected_sil_instr_opcode - msg: >- - expected SIL instruction opcode + msg: "expected SIL instruction opcode" - id: expected_tok_in_sil_instr - msg: >- - expected '%0' in SIL instruction + msg: "expected '%0' in SIL instruction" - id: sil_property_generic_signature_mismatch - msg: >- - sil_property generic signature must match original declaration + msg: "sil_property generic signature must match original declaration" - id: sil_string_no_encoding - msg: >- - string_literal instruction requires an encoding + msg: "string_literal instruction requires an encoding" - id: sil_string_invalid_encoding - msg: >- - unknown string literal encoding '%0' + msg: "unknown string literal encoding '%0'" - id: expected_tuple_type_in_tuple - msg: >- - tuple instruction requires a tuple type + msg: "tuple instruction requires a tuple type" - id: sil_tuple_inst_wrong_value_count - msg: >- - tuple instruction requires %0 values + msg: "tuple instruction requires %0 values" - id: sil_tuple_inst_wrong_field - msg: >- - tuple instruction requires a field number + msg: "tuple instruction requires a field number" - id: sil_struct_inst_wrong_field - msg: >- - struct instruction requires a field name + msg: "struct instruction requires a field name" - id: sil_ref_inst_wrong_field - msg: >- - ref_element_addr instruction requires a field name + msg: "ref_element_addr instruction requires a field name" - id: sil_invalid_instr_operands - msg: >- - invalid instruction operands + msg: "invalid instruction operands" - id: sil_operand_not_address - msg: >- - %0 operand of '%1' must have address type + msg: "%0 operand of '%1' must have address type" - id: sil_operand_not_ref_storage_address - msg: >- - %0 operand of '%1' must have address of %2 type + msg: "%0 operand of '%1' must have address of %2 type" - id: sil_integer_literal_not_integer_type - msg: >- - integer_literal instruction requires a 'Builtin.Int' type + msg: "integer_literal instruction requires a 'Builtin.Int' type" - id: sil_integer_literal_not_well_formed - msg: >- - integer_literal value not well-formed for type %0 + msg: "integer_literal value not well-formed for type %0" - id: sil_float_literal_not_float_type - msg: >- - float_literal instruction requires a 'Builtin.FP' type + msg: "float_literal instruction requires a 'Builtin.FP' type" - id: sil_substitutions_on_non_polymorphic_type - msg: >- - apply of non-polymorphic function cannot have substitutions + msg: "apply of non-polymorphic function cannot have substitutions" - id: sil_witness_method_not_protocol - msg: >- - witness_method is not a protocol method + msg: "witness_method is not a protocol method" - id: sil_witness_method_type_does_not_conform - msg: >- - witness_method type does not conform to protocol + msg: "witness_method type does not conform to protocol" - id: sil_member_decl_not_found - msg: >- - member not found + msg: "member not found" - id: sil_named_member_decl_not_found - msg: >- - member %0 not found in type %1 + msg: "member %0 not found in type %1" - id: sil_member_lookup_bad_type - msg: >- - cannot lookup member %0 in non-nominal, non-module type %1 + msg: "cannot lookup member %0 in non-nominal, non-module type %1" - id: sil_member_decl_type_mismatch - msg: >- - member defined with mismatching type %0 (expected %1) + msg: "member defined with mismatching type %0 (expected %1)" - id: sil_substitution_mismatch - msg: >- - substitution replacement type %0 does not conform to protocol %1 + msg: "substitution replacement type %0 does not conform to protocol %1" - id: sil_not_class - msg: >- - substitution replacement type %0 is not a class type + msg: "substitution replacement type %0 is not a class type" - id: sil_missing_substitutions - msg: >- - missing substitutions + msg: "missing substitutions" - id: sil_too_many_substitutions - msg: >- - too many substitutions + msg: "too many substitutions" - id: sil_dbg_unknown_key - msg: >- - unknown key '%0' in debug variable declaration + msg: "unknown key '%0' in debug variable declaration" - id: sil_objc_with_tail_elements - msg: >- - alloc_ref [objc] cannot have tail allocated elements + msg: "alloc_ref [objc] cannot have tail allocated elements" - id: sil_expected_access_kind - msg: >- - %0 instruction must have explicit access kind + msg: "%0 instruction must have explicit access kind" - id: sil_expected_access_enforcement - msg: >- - %0 instruction must have explicit access enforcement + msg: "%0 instruction must have explicit access enforcement" - id: sil_keypath_expected_component_kind - msg: >- - expected keypath component kind + msg: "expected keypath component kind" - id: sil_keypath_unknown_component_kind - msg: >- - unknown keypath component kind %0 + msg: "unknown keypath component kind %0" - id: sil_keypath_computed_property_missing_part - msg: >- - keypath %select{gettable|settable}0_property component needs an - %select{id and getter|id, getter, and setter}0 + msg: "keypath %select{gettable|settable}0_property component needs an %select{id and getter|id, getter, and setter}0" - id: sil_keypath_no_root - msg: >- - keypath must have a root component declared + msg: "keypath must have a root component declared" - id: sil_keypath_index_not_hashable - msg: >- - key path index type %0 does not conform to Hashable + msg: "key path index type %0 does not conform to Hashable" - id: sil_keypath_index_operand_type_conflict - msg: >- - conflicting types for key path operand %0: %1 vs. %2 + msg: "conflicting types for key path operand %0: %1 vs. %2" - id: sil_keypath_no_use_of_operand_in_pattern - msg: >- - operand %0 is not referenced by any component in the pattern + msg: "operand %0 is not referenced by any component in the pattern" - id: expected_sil_block_name - msg: >- - expected basic block name or '}' + msg: "expected basic block name or '}'" - id: expected_sil_block_colon - msg: >- - expected ':' after basic block name + msg: "expected ':' after basic block name" - id: sil_undefined_basicblock_use - msg: >- - use of undefined basic block %0 + msg: "use of undefined basic block %0" - id: sil_basicblock_redefinition - msg: >- - redefinition of basic block %0 + msg: "redefinition of basic block %0" - id: sil_basicblock_arg_rparen - msg: >- - expected ')' in basic block argument list + msg: "expected ')' in basic block argument list" - id: expected_sil_function_name - msg: >- - expected SIL function name + msg: "expected SIL function name" - id: expected_sil_rbrace - msg: >- - expected '}' at the end of a sil body + msg: "expected '}' at the end of a sil body" - id: expected_sil_function_type - msg: >- - sil function expected to have SIL function type + msg: "sil function expected to have SIL function type" - id: sil_dynamically_replaced_func_not_found - msg: >- - dynamically replaced function not found %0 + msg: "dynamically replaced function not found %0" - id: sil_availability_expected_version - msg: >- - expected version number in 'available' attribute + msg: "expected version number in 'available' attribute" - id: expected_sil_stage_name - msg: >- - expected 'raw' or 'canonical' after 'sil_stage' + msg: "expected 'raw' or 'canonical' after 'sil_stage'" - id: multiple_sil_stage_decls - msg: >- - sil_stage declared multiple times + msg: "sil_stage declared multiple times" - id: expected_sil_vtable_colon - msg: >- - expected ':' in a vtable entry + msg: "expected ':' in a vtable entry" - id: sil_vtable_func_not_found - msg: >- - sil function not found %0 + msg: "sil function not found %0" - id: sil_vtable_class_not_found - msg: >- - sil class not found %0 + msg: "sil class not found %0" - id: sil_vtable_bad_entry_kind - msg: >- - expected 'inherited' or 'override' + msg: "expected 'inherited' or 'override'" - id: sil_vtable_expect_rsquare - msg: >- - expected ']' after vtable entry kind + msg: "expected ']' after vtable entry kind" - id: sil_global_variable_not_found - msg: >- - sil global not found %0 + msg: "sil global not found %0" - id: expected_sil_witness_colon - msg: >- - expected ':' in a witness table + msg: "expected ':' in a witness table" - id: expected_sil_witness_lparen - msg: >- - expected '(' in a witness table + msg: "expected '(' in a witness table" - id: expected_sil_witness_rparen - msg: >- - expected ')' in a witness table + msg: "expected ')' in a witness table" - id: sil_witness_func_not_found - msg: >- - sil function not found %0 + msg: "sil function not found %0" - id: sil_witness_protocol_not_found - msg: >- - sil protocol not found %0 + msg: "sil protocol not found %0" - id: sil_witness_assoc_not_found - msg: >- - sil associated type decl not found %0 + msg: "sil associated type decl not found %0" - id: sil_witness_assoc_conf_not_found - msg: >- - sil associated type path for conformance not found %0 + msg: "sil associated type path for conformance not found %0" - id: sil_witness_protocol_conformance_not_found - msg: >- - sil protocol conformance not found + msg: "sil protocol conformance not found" - id: sil_diff_witness_expected_token - msg: >- - expected '%0' in differentiability witness + msg: "expected '%0' in differentiability witness" - id: sil_diff_witness_serialized_declaration - msg: >- - differentiability witness declaration should not be serialized + msg: "differentiability witness declaration should not be serialized" - id: sil_diff_witness_undefined - msg: >- - reference to undefined differentiability witness + msg: "reference to undefined differentiability witness" - id: sil_diff_witness_invalid_generic_signature - msg: >- - expected witness generic signature '%0' does not have same generic - parameters as original function generic signature '%1' + msg: "expected witness generic signature '%0' does not have same generic parameters as original function generic signature '%1'" - id: sil_coverage_invalid_hash - msg: >- - expected coverage hash + msg: "expected coverage hash" - id: sil_coverage_expected_lbrace - msg: >- - expected '{' in coverage map + msg: "expected '{' in coverage map" - id: sil_coverage_expected_loc - msg: >- - expected line:column pair + msg: "expected line:column pair" - id: sil_coverage_expected_arrow - msg: >- - expected '->' after start location + msg: "expected '->' after start location" - id: sil_coverage_expected_colon - msg: >- - expected ':' after source range + msg: "expected ':' after source range" - id: sil_coverage_invalid_counter - msg: >- - expected counter expression, id, or 'zero' + msg: "expected counter expression, id, or 'zero'" - id: sil_coverage_expected_rparen - msg: >- - expected ')' to end counter expression + msg: "expected ')' to end counter expression" - id: sil_coverage_expected_quote - msg: >- - expected quotes surrounding PGO function name + msg: "expected quotes surrounding PGO function name" - id: sil_coverage_invalid_operator - msg: >- - expected '+' or '-' + msg: "expected '+' or '-'" - id: expected_type - msg: >- - expected type + msg: "expected type" - id: expected_init_value - msg: >- - expected initial value after '=' + msg: "expected initial value after '='" - id: expected_identifier_in_dotted_type - msg: >- - expected identifier in dotted type + msg: "expected identifier in dotted type" - id: expected_identifier_for_type - msg: >- - expected identifier for type name + msg: "expected identifier for type name" - id: expected_rangle_generic_arg_list - msg: >- - expected '>' to complete generic argument list + msg: "expected '>' to complete generic argument list" - id: expected_type_function_result - msg: >- - expected type for function result + msg: "expected type for function result" - id: generic_non_function - msg: >- - only syntactic function types can be generic + msg: "only syntactic function types can be generic" - id: rethrowing_function_type - msg: >- - only function declarations may be marked 'rethrows'; did you mean - 'throws'? + msg: "only function declarations may be marked 'rethrows'; did you mean 'throws'?" - id: async_or_throws_in_wrong_position - msg: >- - %select{'throws'|'rethrows'|'async'}0 may only occur before '->' + msg: "%select{'throws'|'rethrows'|'async'}0 may only occur before '->'" - id: throw_in_function_type - msg: >- - expected throwing specifier; did you mean 'throws'? + msg: "expected throwing specifier; did you mean 'throws'?" - id: expected_type_before_arrow - msg: >- - expected type before '->' + msg: "expected type before '->'" - id: expected_type_after_arrow - msg: >- - expected type after '->' + msg: "expected type after '->'" - id: function_type_argument_label - msg: >- - function types cannot have argument labels; use '_' before %0 + msg: "function types cannot have argument labels; use '_' before %0" - id: expected_dynamic_func_attr - msg: >- - expected a dynamically_replaceable function + msg: "expected a dynamically_replaceable function" + +- id: async_after_throws + msg: "'async' must precede %select{'throws'|'rethrows'}0" + +- id: async_init + msg: "initializer cannot be marked 'async'" - id: expected_expr_enum_case_raw_value - msg: >- - expected expression after '=' in 'case' + msg: "expected expression after '=' in 'case'" - id: nonliteral_enum_case_raw_value - msg: >- - raw value for enum case must be a literal + msg: "raw value for enum case must be a literal" - id: new_array_syntax - msg: >- - array types are now written with the brackets around the element type + msg: "array types are now written with the brackets around the element type" - id: expected_rbracket_array_type - msg: >- - expected ']' in array type + msg: "expected ']' in array type" - id: expected_element_type - msg: >- - expected element type + msg: "expected element type" - id: expected_dictionary_value_type - msg: >- - expected dictionary value type + msg: "expected dictionary value type" - id: expected_rbracket_dictionary_type - msg: >- - expected ']' in dictionary type + msg: "expected ']' in dictionary type" - id: extra_rbracket - msg: >- - unexpected ']' in type; did you mean to write an array type? + msg: "unexpected ']' in type; did you mean to write an array type?" - id: extra_colon - msg: >- - unexpected ':' in type; did you mean to write a dictionary type? + msg: "unexpected ':' in type; did you mean to write a dictionary type?" - id: subscript_array_element - msg: >- - unexpected subscript in array literal; did you mean to write two separate - elements instead? + msg: "unexpected subscript in array literal; did you mean to write two separate elements instead?" - id: subscript_array_element_fix_it_add_comma - msg: >- - add a separator between the elements + msg: "add a separator between the elements" - id: subscript_array_element_fix_it_remove_space - msg: >- - remove the space between the elements to silence this warning + msg: "remove the space between the elements to silence this warning" - id: expected_rparen_tuple_type_list - msg: >- - expected ')' at end of tuple list + msg: "expected ')' at end of tuple list" - id: multiple_ellipsis_in_tuple - msg: >- - only a single element can be variadic + msg: "only a single element can be variadic" - id: tuple_type_init - msg: >- - default argument not permitted in a tuple type + msg: "default argument not permitted in a tuple type" - id: protocol_method_argument_init - msg: >- - default argument not permitted in a protocol method + msg: "default argument not permitted in a protocol method" - id: protocol_init_argument_init - msg: >- - default argument not permitted in a protocol initializer + msg: "default argument not permitted in a protocol initializer" - id: tuple_type_multiple_labels - msg: >- - tuple element cannot have two labels + msg: "tuple element cannot have two labels" - id: expected_rangle_protocol - msg: >- - expected '>' to complete protocol-constrained type + msg: "expected '>' to complete protocol-constrained type" - id: deprecated_protocol_composition - msg: >- - 'protocol<...>' composition syntax has been removed; join the protocols - using '&' + msg: "'protocol<...>' composition syntax has been removed; join the protocols using '&'" - id: deprecated_protocol_composition_single - msg: >- - 'protocol<...>' composition syntax has been removed and is not needed - here + msg: "'protocol<...>' composition syntax has been removed and is not needed here" - id: deprecated_any_composition - msg: >- - 'protocol<>' syntax has been removed; use 'Any' instead + msg: "'protocol<>' syntax has been removed; use 'Any' instead" - id: sil_box_expected_var_or_let - msg: >- - expected 'var' or 'let' to introduce SIL box field type + msg: "expected 'var' or 'let' to introduce SIL box field type" - id: sil_box_expected_r_brace - msg: >- - expected '}' to complete SIL box field type list + msg: "expected '}' to complete SIL box field type list" - id: sil_box_expected_r_angle - msg: >- - expected '>' to complete SIL box generic argument list + msg: "expected '>' to complete SIL box generic argument list" - id: sil_function_subst_expected_l_angle - msg: >- - expected '<' to begin SIL function type substitution list after 'for' + msg: "expected '<' to begin SIL function type substitution list after 'for'" - id: sil_function_subst_expected_r_angle - msg: >- - expected '>' to end SIL function type substitution list after 'for <...' + msg: "expected '>' to end SIL function type substitution list after 'for <...'" - id: sil_function_subst_expected_generics - msg: >- - expected '<' to begin substituted parameter list after '@substituted' + msg: "expected '<' to begin substituted parameter list after '@substituted'" - id: sil_function_subst_expected_function - msg: >- - expected function type after '@substituted' + msg: "expected function type after '@substituted'" - id: sil_function_subst_expected_subs - msg: >- - expected 'for' to begin substitutions after '@substituted' function type + msg: "expected 'for' to begin substitutions after '@substituted' function type" - id: sil_function_subs_without_generics - msg: >- - unexpected 'for' to begin substitutions after non-generic function type + msg: "unexpected 'for' to begin substitutions after non-generic function type" - id: opaque_mid_composition - msg: >- - 'some' should appear at the beginning of a composition + msg: "'some' should appear at the beginning of a composition" - id: layout_size_should_be_positive - msg: >- - expected non-negative size to be specified in layout constraint + msg: "expected non-negative size to be specified in layout constraint" - id: layout_alignment_should_be_positive - msg: >- - expected non-negative alignment to be specified in layout constraint + msg: "expected non-negative alignment to be specified in layout constraint" - id: expected_rparen_layout_constraint - msg: >- - expected ')' to complete layout constraint + msg: "expected ')' to complete layout constraint" - id: layout_constraints_only_inside_specialize_attr - msg: >- - layout constraints are only allowed inside '_specialize' attributes + msg: "layout constraints are only allowed inside '_specialize' attributes" - id: expected_pattern - msg: >- - expected pattern + msg: "expected pattern" - id: keyword_cant_be_identifier - msg: >- - keyword '%0' cannot be used as an identifier here + msg: "keyword '%0' cannot be used as an identifier here" - id: repeated_identifier - msg: >- - found an unexpected second identifier in %0 declaration; is there an - accidental break? + msg: "found an unexpected second identifier in %0 declaration; is there an accidental break?" - id: join_identifiers - msg: >- - join the identifiers together + msg: "join the identifiers together" - id: join_identifiers_camel_case - msg: >- - join the identifiers together with camel-case + msg: "join the identifiers together with camel-case" - id: backticks_to_escape - msg: >- - if this name is unavoidable, use backticks to escape it + msg: "if this name is unavoidable, use backticks to escape it" - id: expected_rparen_tuple_pattern_list - msg: >- - expected ')' at end of tuple pattern + msg: "expected ')' at end of tuple pattern" - id: untyped_pattern_ellipsis - msg: >- - '...' cannot be applied to a subpattern which is not explicitly typed + msg: "'...' cannot be applied to a subpattern which is not explicitly typed" - id: no_default_arg_closure - msg: >- - default arguments are not allowed in closures + msg: "default arguments are not allowed in closures" - id: no_default_arg_curried - msg: >- - default arguments are not allowed in curried parameter lists + msg: "default arguments are not allowed in curried parameter lists" - id: var_pattern_in_var - msg: >- - '%select{var|let}0' cannot appear nested inside another 'var' or 'let' - pattern + msg: "'%select{var|let}0' cannot appear nested inside another 'var' or 'let' pattern" - id: extra_var_in_multiple_pattern_list - msg: >- - %0 must be bound in every pattern + msg: "%0 must be bound in every pattern" - id: let_pattern_in_immutable_context - msg: >- - 'let' pattern cannot appear nested in an already immutable context + msg: "'let' pattern cannot appear nested in an already immutable context" - id: specifier_must_have_type - msg: >- - %0 arguments must have a type specified + msg: "%0 arguments must have a type specified" - id: expected_rparen_parameter - msg: >- - expected ')' in parameter + msg: "expected ')' in parameter" - id: expected_parameter_type - msg: >- - expected parameter type following ':' + msg: "expected parameter type following ':'" - id: expected_parameter_name - msg: >- - expected parameter name followed by ':' + msg: "expected parameter name followed by ':'" - id: expected_parameter_colon - msg: >- - expected ':' following argument label and parameter name + msg: "expected ':' following argument label and parameter name" - id: expected_assignment_instead_of_comparison_operator - msg: >- - expected '=' instead of '==' to assign default value for parameter + msg: "expected '=' instead of '==' to assign default value for parameter" - id: multiple_parameter_ellipsis - msg: >- - only a single variadic parameter '...' is permitted + msg: "only a single variadic parameter '...' is permitted" - id: parameter_vararg_default - msg: >- - variadic parameter cannot have a default value + msg: "variadic parameter cannot have a default value" - id: parameter_specifier_as_attr_disallowed - msg: >- - '%0' before a parameter name is not allowed, place it before the - parameter type instead + msg: "'%0' before a parameter name is not allowed, place it before the parameter type instead" - id: parameter_specifier_repeated - msg: >- - parameter must not have multiple '__owned', 'inout', or '__shared' - specifiers + msg: "parameter must not have multiple '__owned', 'inout', or '__shared' specifiers" - id: parameter_let_var_as_attr - msg: >- - '%0' in this position is interpreted as an argument label + msg: "'%0' in this position is interpreted as an argument label" - id: parameter_extraneous_double_up - msg: >- - extraneous duplicate parameter name; %0 already has an argument label + msg: "extraneous duplicate parameter name; %0 already has an argument label" - id: parameter_operator_keyword_argument - msg: >- - %select{operator|closure|enum case}0 cannot have keyword arguments + msg: "%select{operator|closure|enum case}0 cannot have keyword arguments" - id: parameter_unnamed - msg: >- - unnamed parameters must be written with the empty name '_' + msg: "unnamed parameters must be written with the empty name '_'" - id: parameter_unnamed_warn - msg: >- - unnamed parameters must be written with the empty name '_' + msg: "unnamed parameters must be written with the empty name '_'" - id: parameter_curry_syntax_removed - msg: >- - cannot have more than one parameter list + msg: "cannot have more than one parameter list" - id: initializer_as_typed_pattern - msg: >- - unexpected initializer in pattern; did you mean to use '='? + msg: "unexpected initializer in pattern; did you mean to use '='?" - id: unlabeled_parameter_following_variadic_parameter - msg: >- - a parameter following a variadic parameter requires a label + msg: "a parameter following a variadic parameter requires a label" - id: enum_element_empty_arglist - msg: >- - enum element with associated values must have at least one associated - value + msg: "enum element with associated values must have at least one associated value" - id: enum_element_empty_arglist_swift4 - msg: >- - enum element with associated values must have at least one associated - value; this will be an error in the future version of Swift + msg: "enum element with associated values must have at least one associated value; this will be an error in the future version of Swift" - id: enum_element_empty_arglist_delete - msg: >- - did you mean to remove the empty associated value list? + msg: "did you mean to remove the empty associated value list?" - id: enum_element_empty_arglist_add_void - msg: >- - did you mean to explicitly add a 'Void' associated value? + msg: "did you mean to explicitly add a 'Void' associated value?" - id: expected_stmt - msg: >- - expected statement + msg: "expected statement" - id: illegal_top_level_stmt - msg: >- - statements are not allowed at the top level + msg: "statements are not allowed at the top level" - id: illegal_top_level_expr - msg: >- - expressions are not allowed at the top level + msg: "expressions are not allowed at the top level" - id: illegal_semi_stmt - msg: >- - ';' statements are not allowed + msg: "';' statements are not allowed" - id: statement_begins_with_closure - msg: >- - top-level statement cannot begin with a closure expression + msg: "top-level statement cannot begin with a closure expression" - id: statement_same_line_without_semi - msg: >- - consecutive statements on a line must be separated by ';' + msg: "consecutive statements on a line must be separated by ';'" - id: invalid_label_on_stmt - msg: >- - labels are only valid on loops, if, and switch statements + msg: "labels are only valid on loops, if, and switch statements" - id: labeled_block_needs_do - msg: >- - labeled block needs 'do' + msg: "labeled block needs 'do'" - id: snake_case_deprecated - msg: >- - %0 has been replaced with %1 in Swift 3 + msg: "%0 has been replaced with %1 in Swift 3" - id: expected_expr_assignment - msg: >- - expected expression in assignment + msg: "expected expression in assignment" - id: expected_rbrace_in_brace_stmt - msg: >- - expected '}' at end of brace statement + msg: "expected '}' at end of brace statement" - id: typealias_inside_protocol_without_type - msg: >- - type alias is missing an assigned type; use 'associatedtype' to define an - associated type requirement + msg: "type alias is missing an assigned type; use 'associatedtype' to define an associated type requirement" - id: associatedtype_outside_protocol - msg: >- - associated types can only be defined in a protocol; define a type or - introduce a 'typealias' to satisfy an associated type requirement + msg: "associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement" - id: expected_expr_return - msg: >- - expected expression in 'return' statement + msg: "expected expression in 'return' statement" - id: unindented_code_after_return - msg: >- - expression following 'return' is treated as an argument of the 'return' + msg: "expression following 'return' is treated as an argument of the 'return'" - id: indent_expression_to_silence - msg: >- - indent the expression to silence this warning + msg: "indent the expression to silence this warning" - id: expected_expr_throw - msg: >- - expected expression in 'throw' statement + msg: "expected expression in 'throw' statement" - id: expected_expr_yield - msg: >- - expected expression in 'yield' statement + msg: "expected expression in 'yield' statement" - id: expected_lbrace_after_defer - msg: >- - expected '{' after 'defer' + msg: "expected '{' after 'defer'" - id: expected_comma_stmtcondition - msg: >- - expected ',' joining parts of a multi-clause condition + msg: "expected ',' joining parts of a multi-clause condition" - id: expected_expr_conditional - msg: >- - expected expression in conditional + msg: "expected expression in conditional" - id: expected_binding_keyword - msg: >- - expected '%0' in conditional + msg: "expected '%0' in conditional" - id: expected_expr_conditional_var - msg: >- - expected expression after '=' in conditional binding + msg: "expected expression after '=' in conditional binding" - id: conditional_var_initializer_required - msg: >- - variable binding in a condition requires an initializer + msg: "variable binding in a condition requires an initializer" - id: wrong_condition_case_location - msg: >- - pattern matching binding is spelled with 'case %0', not '%0 case' + msg: "pattern matching binding is spelled with 'case %0', not '%0 case'" - id: expected_condition_if - msg: >- - expected expression, var, or let in 'if' condition + msg: "expected expression, var, or let in 'if' condition" - id: missing_condition_after_if - msg: >- - missing condition in an 'if' statement + msg: "missing condition in an 'if' statement" - id: expected_lbrace_after_if - msg: >- - expected '{' after 'if' condition + msg: "expected '{' after 'if' condition" - id: expected_lbrace_or_if_after_else - msg: >- - expected '{' or 'if' after 'else' + msg: "expected '{' or 'if' after 'else'" - id: expected_lbrace_or_if_after_else_fixit - msg: >- - expected '{' or 'if' after 'else'; did you mean to write 'if'? + msg: "expected '{' or 'if' after 'else'; did you mean to write 'if'?" - id: unexpected_else_after_if - msg: >- - unexpected 'else' immediately following 'if' condition + msg: "unexpected 'else' immediately following 'if' condition" - id: suggest_removing_else - msg: >- - remove 'else' to execute the braced block of statements when the - condition is true + msg: "remove 'else' to execute the braced block of statements when the condition is true" - id: expected_condition_guard - msg: >- - expected expression, var, let or case in 'guard' condition + msg: "expected expression, var, let or case in 'guard' condition" - id: missing_condition_after_guard - msg: >- - missing condition in an 'guard' statement + msg: "missing condition in an 'guard' statement" - id: expected_else_after_guard - msg: >- - expected 'else' after 'guard' condition + msg: "expected 'else' after 'guard' condition" - id: expected_lbrace_after_guard - msg: >- - expected '{' after 'guard' else + msg: "expected '{' after 'guard' else" - id: bound_var_guard_body - msg: >- - variable declared in 'guard' condition is not usable in its body + msg: "variable declared in 'guard' condition is not usable in its body" - id: expected_condition_while - msg: >- - expected expression, var, or let in 'while' condition + msg: "expected expression, var, or let in 'while' condition" - id: missing_condition_after_while - msg: >- - missing condition in a 'while' statement + msg: "missing condition in a 'while' statement" - id: expected_lbrace_after_while - msg: >- - expected '{' after 'while' condition + msg: "expected '{' after 'while' condition" - id: expected_lbrace_after_repeat - msg: >- - expected '{' after 'repeat' + msg: "expected '{' after 'repeat'" - id: expected_while_after_repeat_body - msg: >- - expected 'while' after body of 'repeat' statement + msg: "expected 'while' after body of 'repeat' statement" - id: expected_expr_repeat_while - msg: >- - expected expression in 'repeat-while' condition + msg: "expected expression in 'repeat-while' condition" - id: do_while_now_repeat_while - msg: >- - 'do-while' statement is not allowed + msg: "'do-while' statement is not allowed" - id: do_while_expected_repeat_while - msg: >- - did you mean 'repeat-while' statement? + msg: "did you mean 'repeat-while' statement?" - id: do_while_expected_separate_stmt - msg: >- - did you mean separate 'do' and 'while' statements? + msg: "did you mean separate 'do' and 'while' statements?" - id: expected_lbrace_after_do - msg: >- - expected '{' after 'do' + msg: "expected '{' after 'do'" - id: expected_lbrace_after_catch - msg: >- - expected '{' after 'catch' pattern + msg: "expected '{' after 'catch' pattern" - id: expected_catch_where_expr - msg: >- - expected expression for 'where' guard of 'catch' + msg: "expected expression for 'where' guard of 'catch'" - id: docatch_not_trycatch - msg: >- - the 'do' keyword is used to specify a 'catch' region + msg: "the 'do' keyword is used to specify a 'catch' region" - id: c_style_for_stmt_removed - msg: >- - C-style for statement has been removed in Swift 3 + msg: "C-style for statement has been removed in Swift 3" - id: expected_foreach_in - msg: >- - expected 'in' after for-each pattern + msg: "expected 'in' after for-each pattern" - id: expected_foreach_container - msg: >- - expected Sequence expression for for-each loop + msg: "expected Sequence expression for for-each loop" - id: expected_foreach_lbrace - msg: >- - expected '{' to start the body of for-each loop + msg: "expected '{' to start the body of for-each loop" - id: expected_foreach_where_expr - msg: >- - expected expression in 'where' guard of 'for/in' + msg: "expected expression in 'where' guard of 'for/in'" - id: expected_switch_expr - msg: >- - expected expression in 'switch' statement + msg: "expected expression in 'switch' statement" - id: expected_lbrace_after_switch - msg: >- - expected '{' after 'switch' subject expression + msg: "expected '{' after 'switch' subject expression" - id: expected_rbrace_switch - msg: >- - expected '}' at end of 'switch' statement + msg: "expected '}' at end of 'switch' statement" - id: case_outside_of_switch - msg: >- - '%0' label can only appear inside a 'switch' statement + msg: "'%0' label can only appear inside a 'switch' statement" - id: stmt_in_switch_not_covered_by_case - msg: >- - all statements inside a switch must be covered by a 'case' or 'default' + msg: "all statements inside a switch must be covered by a 'case' or 'default'" - id: case_after_default - msg: >- - additional 'case' blocks cannot appear after the 'default' block of a - 'switch' + msg: "additional 'case' blocks cannot appear after the 'default' block of a 'switch'" - id: expected_case_where_expr - msg: >- - expected expression for 'where' guard of 'case' + msg: "expected expression for 'where' guard of 'case'" - id: expected_case_colon - msg: >- - expected ':' after '%0' + msg: "expected ':' after '%0'" - id: default_with_where - msg: >- - 'default' cannot be used with a 'where' guard expression + msg: "'default' cannot be used with a 'where' guard expression" - id: case_stmt_without_body - msg: >- - %select{'case'|'default'}0 label in a 'switch' should have at least one - executable statement + msg: "%select{'case'|'default'}0 label in a 'switch' should have at least one executable statement" - id: try_on_stmt - msg: >- - 'try' cannot be used with '%0' + msg: "'try' cannot be used with '%0'" - id: try_on_return_throw_yield - msg: >- - 'try' must be placed on the %select{returned|thrown|yielded}0 expression + msg: "'try' must be placed on the %select{returned|thrown|yielded}0 expression" - id: try_on_var_let - msg: >- - 'try' must be placed on the initial value expression + msg: "'try' must be placed on the initial value expression" - id: expected_expr - msg: >- - expected expression + msg: "expected expression" - id: expected_separator - msg: >- - expected '%0' separator + msg: "expected '%0' separator" - id: unexpected_separator - msg: >- - unexpected '%0' separator + msg: "unexpected '%0' separator" - id: expected_expr_after_operator - msg: >- - expected expression after operator + msg: "expected expression after operator" - id: expected_expr_after_unary_operator - msg: >- - expected expression after unary operator + msg: "expected expression after unary operator" - id: expected_prefix_operator - msg: >- - unary operator cannot be separated from its operand + msg: "unary operator cannot be separated from its operand" - id: expected_operator_ref - msg: >- - expected operator name in operator reference + msg: "expected operator name in operator reference" - id: invalid_postfix_operator - msg: >- - operator with postfix spacing cannot start a subexpression + msg: "operator with postfix spacing cannot start a subexpression" - id: expected_member_name - msg: >- - expected member name following '.' + msg: "expected member name following '.'" - id: dollar_numeric_too_large - msg: >- - numeric value following '$' is too large + msg: "numeric value following '$' is too large" - id: numeric_literal_numeric_member - msg: >- - expected named member of numeric literal + msg: "expected named member of numeric literal" - id: standalone_dollar_identifier - msg: >- - '$' is not an identifier; use backticks to escape it + msg: "'$' is not an identifier; use backticks to escape it" - id: dollar_identifier_decl - msg: >- - cannot declare entity named %0; the '$' prefix is reserved for - implicitly-synthesized declarations -- id: lazy_var_storage_access - msg: >- - access to the underlying storage of a lazy property is not allowed + msg: "cannot declare entity named %0; the '$' prefix is reserved for implicitly-synthesized declarations" - id: anon_closure_arg_not_in_closure - msg: >- - anonymous closure argument not contained in a closure + msg: "anonymous closure argument not contained in a closure" - id: anon_closure_arg_in_closure_with_args - msg: >- - anonymous closure arguments cannot be used inside a closure that has - explicit arguments + msg: "anonymous closure arguments cannot be used inside a closure that has explicit arguments" - id: anon_closure_arg_in_closure_with_args_typo - msg: >- - anonymous closure arguments cannot be used inside a closure that has - explicit arguments; did you mean '%0'? + msg: "anonymous closure arguments cannot be used inside a closure that has explicit arguments; did you mean '%0'?" - id: anon_closure_tuple_param_destructuring - msg: >- - closure tuple parameter does not support destructuring + msg: "closure tuple parameter does not support destructuring" - id: expected_closure_parameter_name - msg: >- - expected the name of a closure parameter + msg: "expected the name of a closure parameter" - id: expected_capture_specifier - msg: >- - expected 'weak', 'unowned', or no specifier in capture list + msg: "expected 'weak', 'unowned', or no specifier in capture list" - id: expected_capture_specifier_name - msg: >- - expected name of in closure capture list + msg: "expected name of in closure capture list" - id: expected_init_capture_specifier - msg: >- - expected initializer for closure capture specifier + msg: "expected initializer for closure capture specifier" - id: expected_capture_list_end_rsquare - msg: >- - expected ']' at end of capture list + msg: "expected ']' at end of capture list" - id: cannot_capture_fields - msg: >- - fields may only be captured by assigning to a specific name + msg: "fields may only be captured by assigning to a specific name" - id: expected_closure_result_type - msg: >- - expected closure result type after '->' + msg: "expected closure result type after '->'" - id: expected_closure_in - msg: >- - expected 'in' after the closure signature + msg: "expected 'in' after the closure signature" - id: unexpected_tokens_before_closure_in - msg: >- - unexpected tokens prior to 'in' + msg: "unexpected tokens prior to 'in'" - id: expected_closure_rbrace - msg: >- - expected '}' at end of closure + msg: "expected '}' at end of closure" - id: trailing_closure_after_newlines - msg: >- - braces here form a trailing closure separated from its callee by multiple - newlines + msg: "braces here form a trailing closure separated from its callee by multiple newlines" - id: trailing_closure_callee_here - msg: >- - callee is here + msg: "callee is here" - id: string_literal_no_atsign - msg: >- - string literals in Swift are not preceded by an '@' sign + msg: "string literals in Swift are not preceded by an '@' sign" - id: invalid_float_literal_missing_leading_zero - msg: >- - '.%0' is not a valid floating point literal; it must be written '0.%0' + msg: "'.%0' is not a valid floating point literal; it must be written '0.%0'" - id: availability_query_outside_if_stmt_guard - msg: >- - #available may only be used as condition of an 'if', 'guard' or 'while' - statement + msg: "#available may only be used as condition of an 'if', 'guard' or 'while' statement" - id: empty_arg_label_underscore - msg: >- - an empty argument label is spelled with '_' + msg: "an empty argument label is spelled with '_'" - id: expected_identifier_after_dot_expr - msg: >- - expected identifier after '.' expression + msg: "expected identifier after '.' expression" - id: expected_identifier_after_super_dot_expr - msg: >- - expected identifier or 'init' after super '.' expression + msg: "expected identifier or 'init' after super '.' expression" - id: expected_dot_or_subscript_after_super - msg: >- - expected '.' or '[' after 'super' + msg: "expected '.' or '[' after 'super'" - id: super_in_closure_with_capture - msg: >- - using 'super' in a closure where 'self' is explicitly captured is not yet - supported + msg: "using 'super' in a closure where 'self' is explicitly captured is not yet supported" - id: super_in_closure_with_capture_here - msg: >- - 'self' explicitly captured here + msg: "'self' explicitly captured here" - id: expected_expr_in_expr_list - msg: >- - expected expression in list of expressions + msg: "expected expression in list of expressions" - id: expected_expr_in_collection_literal - msg: >- - expected expression in container literal + msg: "expected expression in container literal" - id: expected_key_in_dictionary_literal - msg: >- - expected key expression in dictionary literal + msg: "expected key expression in dictionary literal" - id: expected_value_in_dictionary_literal - msg: >- - expected value in dictionary literal + msg: "expected value in dictionary literal" - id: expected_colon_in_dictionary_literal - msg: >- - expected ':' in dictionary literal + msg: "expected ':' in dictionary literal" - id: expected_rparen_expr_list - msg: >- - expected ')' in expression list + msg: "expected ')' in expression list" - id: expected_rsquare_expr_list - msg: >- - expected ']' in expression list + msg: "expected ']' in expression list" - id: expected_rsquare_array_expr - msg: >- - expected ']' in container literal expression + msg: "expected ']' in container literal expression" - id: expected_arg_list_in_object_literal - msg: >- - expected argument list in object literal + msg: "expected argument list in object literal" - id: legacy_object_literal - msg: >- - '%select{|[}0#%1(...)%select{|#]}0' has been renamed to '#%2(...)' + msg: "'%select{|[}0#%1(...)%select{|#]}0' has been renamed to '#%2(...)'" - id: unknown_pound_expr - msg: >- - use of unknown directive '#%0' + msg: "use of unknown directive '#%0'" - id: expected_expr_after_if_question - msg: >- - expected expression after '?' in ternary expression + msg: "expected expression after '?' in ternary expression" - id: expected_colon_after_if_question - msg: >- - expected ':' after '? ...' in ternary expression + msg: "expected ':' after '? ...' in ternary expression" - id: expected_expr_after_if_colon - msg: >- - expected expression after '? ... :' in ternary expression + msg: "expected expression after '? ... :' in ternary expression" + +- id: expected_expr_after_try + msg: "expected expression after 'try'" + +- id: expected_expr_after_await + msg: "expected expression after 'await'" - id: expected_type_after_is - msg: >- - expected type after 'is' + msg: "expected type after 'is'" - id: expected_type_after_as - msg: >- - expected type after 'as' + msg: "expected type after 'as'" - id: string_interpolation_extra - msg: >- - extra tokens after interpolated string expression + msg: "extra tokens after interpolated string expression" - id: string_interpolation_list_changing - msg: >- - interpolating multiple values will not form a tuple in Swift 5 + msg: "interpolating multiple values will not form a tuple in Swift 5" - id: string_interpolation_list_insert_parens - msg: >- - insert parentheses to keep current behavior + msg: "insert parentheses to keep current behavior" - id: string_interpolation_label_changing - msg: >- - labeled interpolations will not be ignored in Swift 5 + msg: "labeled interpolations will not be ignored in Swift 5" - id: string_interpolation_remove_label - msg: >- - remove %0 label to keep current behavior + msg: "remove %0 label to keep current behavior" - id: expr_keypath_expected_lparen - msg: >- - expected '(' following '#keyPath' + msg: "expected '(' following '#keyPath'" - id: expr_keypath_expected_property_or_type - msg: >- - expected property or type name within '#keyPath(...)' + msg: "expected property or type name within '#keyPath(...)'" - id: expr_keypath_expected_rparen - msg: >- - expected ')' to complete '#keyPath' expression + msg: "expected ')' to complete '#keyPath' expression" - id: expr_keypath_expected_expr - msg: >- - expected expression path in Swift key path + msg: "expected expression path in Swift key path" - id: expr_selector_expected_lparen - msg: >- - expected '(' following '#selector' + msg: "expected '(' following '#selector'" - id: expr_selector_expected_method_expr - msg: >- - expected expression naming a method within '#selector(...)' + msg: "expected expression naming a method within '#selector(...)'" - id: expr_selector_expected_property_expr - msg: >- - expected expression naming a property within '#selector(...)' + msg: "expected expression naming a property within '#selector(...)'" - id: expr_selector_expected_rparen - msg: >- - expected ')' to complete '#selector' expression + msg: "expected ')' to complete '#selector' expression" - id: expr_dynamictype_deprecated - msg: >- - '.dynamicType' is deprecated. Use 'type(of: ...)' instead + msg: "'.dynamicType' is deprecated. Use 'type(of: ...)' instead" - id: pound_assert_disabled - msg: >- - #assert is an experimental feature that is currently disabled + msg: "#assert is an experimental feature that is currently disabled" - id: pound_assert_expected_lparen - msg: >- - expected '(' in #assert directive + msg: "expected '(' in #assert directive" - id: pound_assert_expected_rparen - msg: >- - expected ')' in #assert directive + msg: "expected ')' in #assert directive" - id: pound_assert_expected_expression - msg: >- - expected a condition expression + msg: "expected a condition expression" - id: pound_assert_expected_string_literal - msg: >- - expected a string literal + msg: "expected a string literal" - id: replace_equal_with_colon_for_value - msg: >- - '=' has been replaced with ':' in attribute arguments + msg: "'=' has been replaced with ':' in attribute arguments" - id: expected_attribute_name - msg: >- - expected an attribute name + msg: "expected an attribute name" - id: unknown_attribute - msg: >- - unknown attribute '%0' + msg: "unknown attribute '%0'" - id: unexpected_lparen_in_attribute - msg: >- - unexpected '(' in attribute '%0' + msg: "unexpected '(' in attribute '%0'" - id: duplicate_attribute - msg: >- - duplicate %select{attribute|modifier}0 + msg: "duplicate %select{attribute|modifier}0" - id: previous_attribute - msg: >- - %select{attribute|modifier}0 already specified here + msg: "%select{attribute|modifier}0 already specified here" - id: mutually_exclusive_attrs - msg: >- - '%0' contradicts previous %select{attribute|modifier}2 '%1' + msg: "'%0' contradicts previous %select{attribute|modifier}2 '%1'" - id: invalid_infix_on_func - msg: >- - 'infix' modifier is not required or allowed on func declarations + msg: "'infix' modifier is not required or allowed on func declarations" - id: expected_in_attribute_list - msg: >- - expected ']' or ',' in attribute list + msg: "expected ']' or ',' in attribute list" - id: type_attribute_applied_to_decl - msg: >- - attribute can only be applied to types, not declarations + msg: "attribute can only be applied to types, not declarations" - id: decl_attribute_applied_to_type - msg: >- - attribute can only be applied to declarations, not types + msg: "attribute can only be applied to declarations, not types" - id: attr_expected_lparen - msg: >- - expected '(' in '%0' %select{attribute|modifier}1 + msg: "expected '(' in '%0' %select{attribute|modifier}1" - id: attr_expected_rparen - msg: >- - expected ')' in '%0' %select{attribute|modifier}1 + msg: "expected ')' in '%0' %select{attribute|modifier}1" - id: attr_expected_comma - msg: >- - expected ',' in '%0' %select{attribute|modifier}1 + msg: "expected ',' in '%0' %select{attribute|modifier}1" - id: attr_expected_string_literal - msg: >- - expected string literal in '%0' attribute + msg: "expected string literal in '%0' attribute" - id: attr_missing_label - msg: >- - missing label '%0:' in '@%1' attribute + msg: "missing label '%0:' in '@%1' attribute" - id: attr_expected_label - msg: >- - expected label '%0:' in '@%1' attribute + msg: "expected label '%0:' in '@%1' attribute" - id: alignment_must_be_positive_integer - msg: >- - alignment value must be a positive integer literal + msg: "alignment value must be a positive integer literal" - id: swift_native_objc_runtime_base_must_be_identifier - msg: >- - @_swift_native_objc_runtime_base class name must be an identifier + msg: "@_swift_native_objc_runtime_base class name must be an identifier" - id: objc_runtime_name_must_be_identifier - msg: >- - @_objcRuntimeName name must be an identifier + msg: "@_objcRuntimeName name must be an identifier" - id: attr_only_at_non_local_scope - msg: >- - attribute '%0' can only be used in a non-local scope + msg: "attribute '%0' can only be used in a non-local scope" - id: projection_value_property_not_identifier - msg: >- - @_projectedValueProperty name must be an identifier + msg: "@_projectedValueProperty name must be an identifier" - id: attr_access_expected_set - msg: >- - expected 'set' as subject of '%0' modifier + msg: "expected 'set' as subject of '%0' modifier" - id: attr_access_expected_spi_name - msg: >- - expected an SPI identifier as subject of the '@_spi' attribute + msg: "expected an SPI identifier as subject of the '@_spi' attribute" - id: attr_renamed - msg: >- - '@%0' has been renamed to '@%1' + msg: "'@%0' has been renamed to '@%1'" - id: attr_renamed_warning - msg: >- - '@%0' has been renamed to '@%1' + msg: "'@%0' has been renamed to '@%1'" - id: attr_name_close_match - msg: >- - no attribute named '@%0'; did you mean '@%1'? + msg: "no attribute named '@%0'; did you mean '@%1'?" - id: attr_unsupported_on_target - msg: >- - attribute '%0' is unsupported on target '%1' + msg: "attribute '%0' is unsupported on target '%1'" - id: attr_availability_platform - msg: >- - expected platform name or '*' for '%0' attribute + msg: "expected platform name or '*' for '%0' attribute" - id: attr_availability_unavailable_deprecated - msg: >- - '%0' attribute cannot be both unconditionally 'unavailable' and - 'deprecated' + msg: "'%0' attribute cannot be both unconditionally 'unavailable' and 'deprecated'" - id: attr_availability_invalid_duplicate - msg: >- - '%0' argument has already been specified + msg: "'%0' argument has already been specified" - id: attr_availability_unknown_platform - msg: >- - unknown platform '%0' for attribute '%1' + msg: "unknown platform '%0' for attribute '%1'" - id: attr_availability_invalid_renamed - msg: >- - 'renamed' argument of '%0' attribute must be an operator, identifier, or - full function name, optionally prefixed by a type name + msg: "'renamed' argument of '%0' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name" - id: attr_availability_expected_option - msg: >- - expected '%0' option such as 'unavailable', 'introduced', 'deprecated', - 'obsoleted', 'message', or 'renamed' + msg: "expected '%0' option such as 'unavailable', 'introduced', 'deprecated', 'obsoleted', 'message', or 'renamed'" - id: attr_availability_expected_equal - msg: >- - expected ':' after '%1' in '%0' attribute + msg: "expected ':' after '%1' in '%0' attribute" - id: attr_availability_expected_version - msg: >- - expected version number in '%0' attribute + msg: "expected version number in '%0' attribute" - id: attr_availability_platform_agnostic_expected_option - msg: >- - expected 'introduced', 'deprecated', or 'obsoleted' in '%0' attribute for - platform '%1' + msg: "expected 'introduced', 'deprecated', or 'obsoleted' in '%0' attribute for platform '%1'" - id: attr_availability_platform_agnostic_expected_deprecated_version - msg: >- - expected version number with 'deprecated' in '%0' attribute for platform - '%1' + msg: "expected version number with 'deprecated' in '%0' attribute for platform '%1'" - id: attr_availability_platform_agnostic_infeasible_option - msg: >- - '%0' cannot be used in '%1' attribute for platform '%2' + msg: "'%0' cannot be used in '%1' attribute for platform '%2'" - id: attr_availability_nonspecific_platform_unexpected_version - msg: >- - unexpected version number in '%0' attribute for non-specific platform '*' + msg: "unexpected version number in '%0' attribute for non-specific platform '*'" - id: originally_defined_in_missing_rparen - msg: >- - expected ')' in @_originallyDefinedIn argument list + msg: "expected ')' in @_originallyDefinedIn argument list" - id: originally_defined_in_unrecognized_platform - msg: >- - unrecognized platform name in @_originallyDefinedIn argument list + msg: "unrecognized platform name in @_originallyDefinedIn argument list" - id: originally_defined_in_unrecognized_property - msg: >- - unrecognized property in @_originallyDefinedIn argument list + msg: "unrecognized property in @_originallyDefinedIn argument list" - id: originally_defined_in_need_original_module_name - msg: >- - expected 'module: "original"' in the first argument to - @_originallyDefinedIn + msg: "expected 'module: \"original\"' in the first argument to @_originallyDefinedIn" - id: originally_defined_in_need_nonempty_module_name - msg: >- - original module name cannot be empty in @_originallyDefinedIn + msg: "original module name cannot be empty in @_originallyDefinedIn" - id: originally_defined_in_need_platform_version - msg: >- - expected at least one platform version in @_originallyDefinedIn + msg: "expected at least one platform version in @_originallyDefinedIn" - id: originally_defined_in_major_minor_only - msg: >- - @_originallyDefinedIn only uses major and minor version number + msg: "@_originallyDefinedIn only uses major and minor version number" - id: originally_defined_in_missing_platform_name - msg: >- - * as platform name has no effect + msg: "* as platform name has no effect" - id: convention_attribute_expected_lparen - msg: >- - expected '(' after 'convention' attribute + msg: "expected '(' after 'convention' attribute" - id: convention_attribute_expected_name - msg: >- - expected convention name identifier in 'convention' attribute + msg: "expected convention name identifier in 'convention' attribute" - id: convention_attribute_expected_rparen - msg: >- - expected ')' after convention name for 'convention' attribute + msg: "expected ')' after convention name for 'convention' attribute" - id: convention_attribute_ctype_expected_label - msg: >- - expected 'cType' label in 'convention' attribute + msg: "expected 'cType' label in 'convention' attribute" - id: convention_attribute_ctype_expected_colon - msg: >- - expected ':' after 'cType' for 'convention' attribute + msg: "expected ':' after 'cType' for 'convention' attribute" - id: convention_attribute_ctype_expected_string - msg: >- - expected string literal containing clang type for 'cType' in 'convention' - attribute + msg: "expected string literal containing clang type for 'cType' in 'convention' attribute" - id: convention_attribute_witness_method_expected_colon - msg: >- - expected ':' after 'witness_method' for 'convention' attribute + msg: "expected ':' after 'witness_method' for 'convention' attribute" - id: convention_attribute_witness_method_expected_protocol - msg: >- - expected protocol name in 'witness_method' 'convention' attribute + msg: "expected protocol name in 'witness_method' 'convention' attribute" - id: attr_objc_missing_colon - msg: >- - missing ':' after selector piece in @objc attribute + msg: "missing ':' after selector piece in @objc attribute" - id: attr_objc_expected_rparen - msg: >- - expected ')' after name for @objc + msg: "expected ')' after name for @objc" - id: attr_objc_empty_name - msg: >- - expected name within parentheses of @objc attribute + msg: "expected name within parentheses of @objc attribute" - id: attr_dynamic_replacement_expected_rparen - msg: >- - expected ')' after function name for @_dynamicReplacement + msg: "expected ')' after function name for @_dynamicReplacement" - id: attr_dynamic_replacement_expected_function - msg: >- - expected a function name in @_dynamicReplacement(for:) + msg: "expected a function name in @_dynamicReplacement(for:)" - id: attr_dynamic_replacement_expected_for - msg: >- - expected 'for' in '_dynamicReplacement' attribute + msg: "expected 'for' in '_dynamicReplacement' attribute" - id: attr_dynamic_replacement_expected_colon - msg: >- - expected ':' after @_dynamicReplacement(for + msg: "expected ':' after @_dynamicReplacement(for" - id: attr_type_eraser_expected_type_name - msg: >- - expected a type name in @_typeEraser() + msg: "expected a type name in @_typeEraser()" - id: attr_type_eraser_expected_rparen - msg: >- - expected ')' after type name for @_typeEraser + msg: "expected ')' after type name for @_typeEraser" - id: attr_private_import_expected_rparen - msg: >- - expected ')' after function name for @_private + msg: "expected ')' after function name for @_private" - id: attr_private_import_expected_sourcefile - msg: >- - expected 'sourceFile' in '_private' attribute + msg: "expected 'sourceFile' in '_private' attribute" - id: attr_private_import_expected_sourcefile_name - msg: >- - expected a source file name in @_private(sourceFile:) + msg: "expected a source file name in @_private(sourceFile:)" - id: attr_private_import_expected_colon - msg: >- - expected ':' after @_private(sourceFile + msg: "expected ':' after @_private(sourceFile" - id: opened_attribute_expected_lparen - msg: >- - expected '(' after 'opened' attribute + msg: "expected '(' after 'opened' attribute" - id: opened_attribute_id_value - msg: >- - known id for 'opened' attribute must be a UUID string + msg: "known id for 'opened' attribute must be a UUID string" - id: opened_attribute_expected_rparen - msg: >- - expected ')' after id value for 'opened' attribute + msg: "expected ')' after id value for 'opened' attribute" - id: optimization_attribute_expect_option - msg: >- - expected '%0' option such as '%1' + msg: "expected '%0' option such as '%1'" - id: optimization_attribute_unknown_option - msg: >- - unknown option '%0' for attribute '%1' + msg: "unknown option '%0' for attribute '%1'" - id: effects_attribute_expect_option - msg: >- - expected '%0' option (readnone, readonly, readwrite) + msg: "expected '%0' option (readnone, readonly, readwrite)" - id: effects_attribute_unknown_option - msg: >- - unknown option '%0' for attribute '%1' + msg: "unknown option '%0' for attribute '%1'" - id: attr_unowned_invalid_specifier - msg: >- - expected 'safe' or 'unsafe' + msg: "expected 'safe' or 'unsafe'" - id: attr_unowned_expected_rparen - msg: >- - expected ')' after specifier for 'unowned' + msg: "expected ')' after specifier for 'unowned'" - id: attr_warn_unused_result_removed - msg: >- - 'warn_unused_result' attribute behavior is now the default + msg: "'warn_unused_result' attribute behavior is now the default" - id: attr_warn_unused_result_expected_rparen - msg: >- - expected ')' after 'warn_unused_result' attribute + msg: "expected ')' after 'warn_unused_result' attribute" - id: attr_specialize_missing_colon - msg: >- - missing ':' after %0 in '_specialize' attribute + msg: "missing ':' after %0 in '_specialize' attribute" - id: attr_specialize_missing_comma - msg: >- - missing ',' in '_specialize' attribute + msg: "missing ',' in '_specialize' attribute" - id: attr_specialize_unknown_parameter_name - msg: >- - unknown parameter %0 in '_specialize attribute' + msg: "unknown parameter %0 in '_specialize attribute'" - id: attr_specialize_expected_bool_value - msg: >- - expected a boolean true or false value in '_specialize' attribute + msg: "expected a boolean true or false value in '_specialize' attribute" - id: attr_specialize_export_true_no_op - msg: >- - 'exported: true' has no effect in '_specialize' attribute + msg: "'exported: true' has no effect in '_specialize' attribute" - id: attr_specialize_missing_parameter_label_or_where_clause - msg: >- - expected a parameter label or a where clause in '_specialize' attribute + msg: "expected a parameter label or a where clause in '_specialize' attribute" - id: attr_specialize_parameter_already_defined - msg: >- - parameter '%0' was already defined in '_specialize' attribute + msg: "parameter '%0' was already defined in '_specialize' attribute" - id: attr_specialize_expected_partial_or_full - msg: >- - expected 'partial' or 'full' as values of the 'kind' parameter in - '_specialize' attribute + msg: "expected 'partial' or 'full' as values of the 'kind' parameter in '_specialize' attribute" - id: attr_implements_expected_member_name - msg: >- - expected a member name as second parameter in '_implements' attribute + msg: "expected a member name as second parameter in '_implements' attribute" - id: attr_differentiable_expected_parameter_list - msg: >- - expected a list of parameters to differentiate with respect to + msg: "expected a list of parameters to differentiate with respect to" - id: attr_differentiable_use_wrt_not_withrespectto - msg: >- - use 'wrt:' to specify parameters to differentiate with respect to + msg: "use 'wrt:' to specify parameters to differentiate with respect to" - id: attr_differentiable_expected_label - msg: >- - expected 'wrt:' or 'where' in '@differentiable' attribute + msg: "expected 'wrt:' or 'where' in '@differentiable' attribute" - id: attr_differentiable_unexpected_argument - msg: >- - unexpected argument '%0' in '@differentiable' attribute + msg: "unexpected argument '%0' in '@differentiable' attribute" - id: expected_colon_after_label - msg: >- - expected a colon ':' after '%0' + msg: "expected a colon ':' after '%0'" - id: diff_params_clause_expected_parameter - msg: >- - expected a parameter, which can be a function parameter name, parameter - index, or 'self' + msg: "expected a parameter, which can be a function parameter name, parameter index, or 'self'" - id: diff_params_clause_expected_parameter_unnamed - msg: >- - expected a parameter, which can be a function parameter index or 'self' + msg: "expected a parameter, which can be a function parameter index or 'self'" - id: autodiff_attr_expected_original_decl_name - msg: >- - expected an original function name + msg: "expected an original function name" - id: sil_autodiff_expected_lsquare - msg: >- - expected '[' to start the %0 + msg: "expected '[' to start the %0" - id: sil_autodiff_expected_rsquare - msg: >- - expected ']' to complete the %0 + msg: "expected ']' to complete the %0" - id: sil_autodiff_expected_index_list - msg: >- - expected a space-separated list of indices, e.g. '0 1' + msg: "expected a space-separated list of indices, e.g. '0 1'" - id: sil_autodiff_expected_index_list_label - msg: >- - expected label '%0' in index list + msg: "expected label '%0' in index list" - id: sil_autodiff_expected_parameter_index - msg: >- - expected the index of a parameter to differentiate with respect to + msg: "expected the index of a parameter to differentiate with respect to" - id: sil_autodiff_expected_result_index - msg: >- - expected the index of a result to differentiate from + msg: "expected the index of a result to differentiate from" - id: sil_inst_autodiff_operand_list_expected_lbrace - msg: >- - expected '{' to start a derivative function list + msg: "expected '{' to start a derivative function list" - id: sil_inst_autodiff_operand_list_expected_comma - msg: >- - expected ',' between operands in a derivative function list + msg: "expected ',' between operands in a derivative function list" - id: sil_inst_autodiff_operand_list_expected_rbrace - msg: >- - expected '}' to start a derivative function list + msg: "expected '}' to start a derivative function list" - id: sil_inst_autodiff_expected_differentiable_extractee_kind - msg: >- - expected an extractee kind attribute, which can be one of '[original]', - '[jvp]', and '[vjp]' + msg: "expected an extractee kind attribute, which can be one of '[original]', '[jvp]', and '[vjp]'" - id: sil_inst_autodiff_expected_linear_extractee_kind - msg: >- - expected an extractee kind attribute, which can be one of '[original]' - and '[transpose]' + msg: "expected an extractee kind attribute, which can be one of '[original]' and '[transpose]'" - id: sil_inst_autodiff_expected_function_type_operand - msg: >- - expected an operand of a function type + msg: "expected an operand of a function type" - id: sil_inst_autodiff_expected_differentiability_witness_kind - msg: >- - expected a differentiability witness kind, which can be one of '[jvp]', - '[vjp]', or '[transpose]' + msg: "expected a differentiability witness kind, which can be one of '[jvp]', '[vjp]', or '[transpose]'" - id: sil_inst_autodiff_invalid_witness_generic_signature - msg: >- - expected witness_generic signature '%0' does not have same generic - parameters as original function generic signature '%1' + msg: "expected witness_generic signature '%0' does not have same generic parameters as original function generic signature '%1'" - id: expected_rangle_generics_param - msg: >- - expected '>' to complete generic parameter list + msg: "expected '>' to complete generic parameter list" - id: expected_generics_parameter_name - msg: >- - expected an identifier to name generic parameter + msg: "expected an identifier to name generic parameter" - id: unexpected_class_constraint - msg: >- - 'class' constraint can only appear on protocol declarations + msg: "'class' constraint can only appear on protocol declarations" - id: suggest_anyobject - msg: >- - did you mean to write an 'AnyObject' constraint? + msg: "did you mean to write an 'AnyObject' constraint?" - id: expected_generics_type_restriction - msg: >- - expected a class type or protocol-constrained type restricting %0 + msg: "expected a class type or protocol-constrained type restricting %0" - id: requires_single_equal - msg: >- - use '==' for same-type requirements rather than '=' + msg: "use '==' for same-type requirements rather than '='" - id: requires_comma - msg: >- - expected ',' to separate the requirements of this 'where' clause + msg: "expected ',' to separate the requirements of this 'where' clause" - id: expected_requirement_delim - msg: >- - expected ':' or '==' to indicate a conformance or same-type requirement + msg: "expected ':' or '==' to indicate a conformance or same-type requirement" - id: redundant_class_requirement - msg: >- - redundant 'class' requirement + msg: "redundant 'class' requirement" - id: late_class_requirement - msg: >- - 'class' must come first in the requirement list + msg: "'class' must come first in the requirement list" - id: where_inside_brackets - msg: >- - 'where' clause next to generic parameters is obsolete, must be written - following the declaration's type + msg: "'where' clause next to generic parameters is obsolete, must be written following the declaration's type" - id: unsupported_conditional_compilation_binary_expression - msg: >- - expected '&&' or '||' expression + msg: "expected '&&' or '||' expression" - id: unsupported_conditional_compilation_unary_expression - msg: >- - expected unary '!' expression + msg: "expected unary '!' expression" - id: unsupported_platform_condition_expression - msg: >- - unexpected platform condition (expected 'os', 'arch', or 'swift') + msg: "unexpected platform condition (expected 'os', 'arch', or 'swift')" - id: platform_condition_expected_one_argument - msg: >- - expected only one argument to platform condition + msg: "expected only one argument to platform condition" - id: unsupported_platform_runtime_condition_argument - msg: >- - unexpected argument for the '_runtime' condition; expected '_Native' or - '_ObjC' + msg: "unexpected argument for the '_runtime' condition; expected '_Native' or '_ObjC'" - id: unsupported_platform_condition_argument - msg: >- - unexpected platform condition argument: expected %0 + msg: "unexpected platform condition argument: expected %0" - id: unsupported_conditional_compilation_expression_type - msg: >- - invalid conditional compilation expression + msg: "invalid conditional compilation expression" - id: unsupported_conditional_compilation_integer - msg: >- - '%0' is not a valid conditional compilation expression, use '%1' + msg: "'%0' is not a valid conditional compilation expression, use '%1'" - id: version_component_not_number - msg: >- - version component contains non-numeric characters + msg: "version component contains non-numeric characters" - id: compiler_version_too_many_components - msg: >- - compiler version must not have more than five components + msg: "compiler version must not have more than five components" - id: unused_compiler_version_component - msg: >- - the second version component is not used for comparison + msg: "the second version component is not used for comparison" - id: empty_version_component - msg: >- - found empty version component + msg: "found empty version component" - id: compiler_version_component_out_of_range - msg: >- - compiler version component out of range: must be in [0, %0] + msg: "compiler version component out of range: must be in [0, %0]" - id: empty_version_string - msg: >- - version requirement is empty + msg: "version requirement is empty" - id: unknown_platform_condition_argument - msg: >- - unknown %0 for build configuration '%1' + msg: "unknown %0 for build configuration '%1'" - id: renamed_platform_condition_argument - msg: >- - '%0' has been renamed to '%1' + msg: "'%0' has been renamed to '%1'" - id: likely_simulator_platform_condition - msg: >- - platform condition appears to be testing for simulator environment; use - 'targetEnvironment(simulator)' instead + msg: "platform condition appears to be testing for simulator environment; use 'targetEnvironment(simulator)' instead" - id: avail_query_expected_condition - msg: >- - expected availability condition + msg: "expected availability condition" - id: avail_query_expected_platform_name - msg: >- - expected platform name + msg: "expected platform name" - id: avail_query_expected_version_number - msg: >- - expected version number + msg: "expected version number" - id: avail_query_expected_rparen - msg: >- - expected ')' in availability query + msg: "expected ')' in availability query" - id: avail_query_unrecognized_platform_name - msg: >- - unrecognized platform name %0 + msg: "unrecognized platform name %0" - id: avail_query_disallowed_operator - msg: >- - '%0' cannot be used in an availability condition + msg: "'%0' cannot be used in an availability condition" - id: avail_query_argument_and_shorthand_mix_not_allowed - msg: >- - '%0' can't be combined with shorthand specification '%1' + msg: "'%0' can't be combined with shorthand specification '%1'" - id: avail_query_meant_introduced - msg: >- - did you mean to specify an introduction version? + msg: "did you mean to specify an introduction version?" - id: avail_query_version_comparison_not_needed - msg: >- - version comparison not needed + msg: "version comparison not needed" - id: availability_query_wildcard_required - msg: >- - must handle potential future platforms with '*' + msg: "must handle potential future platforms with '*'" - id: availability_must_occur_alone - msg: >- - '%0' version-availability must be specified alone + msg: "'%0' version-availability must be specified alone" - id: pound_available_swift_not_allowed - msg: >- - Swift language version checks not allowed in #available(...) + msg: "Swift language version checks not allowed in #available(...)" - id: pound_available_package_description_not_allowed - msg: >- - PackageDescription version checks not allowed in #available(...) + msg: "PackageDescription version checks not allowed in #available(...)" - id: availability_query_repeated_platform - msg: >- - version for '%0' already specified + msg: "version for '%0' already specified" - id: unknown_syntax_entity - msg: >- - unknown %0 syntax exists in the source + msg: "unknown %0 syntax exists in the source" - id: expected_argument_label_followed_by_closure_literal - msg: >- - expected an argument label followed by a closure literal + msg: "expected an argument label followed by a closure literal" - id: expected_closure_literal - msg: >- - expected a closure literal + msg: "expected a closure literal" - id: expected_multiple_closures_block_rbrace - msg: >- - expected '}' at the end of a trailing closures block + msg: "expected '}' at the end of a trailing closures block" - id: decl_declared_here - msg: >- - %0 declared here + msg: "%0 declared here" - id: kind_declared_here - msg: >- - %0 declared here + msg: "%0 declared here" - id: implicit_member_declared_here - msg: >- - %1 '%0' is implicitly declared + msg: "%1 '%0' is implicitly declared" - id: extended_type_declared_here - msg: >- - extended type declared here + msg: "extended type declared here" - id: opaque_return_type_declared_here - msg: >- - opaque return type declared here + msg: "opaque return type declared here" - id: ambiguous_member_overload_set - msg: >- - ambiguous reference to member %0 + msg: "ambiguous reference to member %0" - id: ambiguous_reference_to_decl - msg: >- - ambiguous reference to %0 %1 + msg: "ambiguous reference to %0 %1" - id: no_overloads_match_exactly_in_call - msg: >- - no exact matches in %select{reference|call}0 to %1 %select{%3|}2 + msg: "no exact matches in %select{reference|call}0 to %1 %select{%3|}2" - id: candidate_partial_match - msg: >- - candidate has partially matching parameter list %0 + msg: "candidate has partially matching parameter list %0" - id: could_not_find_value_subscript - msg: >- - value of type %0 has no subscripts + msg: "value of type %0 has no subscripts" - id: could_not_find_tuple_member - msg: >- - value of tuple type %0 has no member %1 + msg: "value of tuple type %0 has no member %1" - id: could_not_find_value_member - msg: >- - value of type %0 has no member %1 + msg: "value of type %0 has no member %1" - id: could_not_find_value_member_corrected - msg: >- - value of type %0 has no member %1; did you mean %2? + msg: "value of type %0 has no member %1; did you mean %2?" - id: could_not_find_value_dynamic_member_corrected - msg: >- - value of type %0 has no dynamic member %2 using key path from root type - %1; did you mean %3? + msg: "value of type %0 has no dynamic member %2 using key path from root type %1; did you mean %3?" - id: could_not_find_value_dynamic_member - msg: >- - value of type %0 has no dynamic member %2 using key path from root type - %1 + msg: "value of type %0 has no dynamic member %2 using key path from root type %1" - id: cannot_infer_contextual_keypath_type_specify_root - msg: >- - cannot infer key path type from context; consider explicitly specifying a - root type + msg: "cannot infer key path type from context; consider explicitly specifying a root type" - id: cannot_infer_keypath_root_anykeypath_context - msg: >- - 'AnyKeyPath' does not provide enough context for root type to be - inferred; consider explicitly specifying a root type + msg: "'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type" - id: could_not_find_type_member - msg: >- - type %0 has no member %1 + msg: "type %0 has no member %1" - id: could_not_find_type_member_corrected - msg: >- - type %0 has no member %1; did you mean %2? + msg: "type %0 has no member %1; did you mean %2?" - id: could_not_find_subscript_member_did_you_mean - msg: >- - value of type %0 has no property or method named 'subscript'; did you - mean to use the subscript operator? + msg: "value of type %0 has no property or method named 'subscript'; did you mean to use the subscript operator?" - id: could_not_find_subscript_member_tuple - msg: >- - cannot access element using subscript for tuple type %0; use '.' notation instead + msg: "cannot access element using subscript for tuple type %0; use '.' notation instead" - id: could_not_find_subscript_member_tuple_did_you_mean_use_dot - msg: >- - cannot access element using subscript for tuple type %0; did you mean to use '.%1'? + msg: "cannot access element using subscript for tuple type %0; did you mean to use '.%1'?" - id: could_not_find_enum_case - msg: >- - enum type %0 has no case %1; did you mean %2? + msg: "enum type %0 has no case %1; did you mean %2?" - id: did_you_mean_raw_type - msg: >- - did you mean to specify a raw type on the enum declaration? + msg: "did you mean to specify a raw type on the enum declaration?" - id: did_you_mean_generic_param_as_conformance - msg: >- - did you mean to declare %0 as a protocol conformance for %1? + msg: "did you mean to declare %0 as a protocol conformance for %1?" - id: any_as_anyobject_fixit - msg: >- - cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more - specific type to access members + msg: "cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members" - id: expected_argument_in_contextual_member - msg: >- - member %0 expects argument of type %1 + msg: "member %0 expects argument of type %1" - id: expected_parens_in_contextual_member - msg: >- - member %0 is a function; did you mean to call it? + msg: "member %0 is a function; did you mean to call it?" - id: expected_result_in_contextual_member - msg: >- - member %0 in %2 produces result of type %1, but context expects %2 + msg: "member %0 in %2 produces result of type %1, but context expects %2" - id: unexpected_arguments_in_enum_case - msg: >- - enum case %0 has no associated values + msg: "enum case %0 has no associated values" - id: could_not_use_type_member_on_instance - msg: >- - static member %1 cannot be used on instance of type %0 + msg: "static member %1 cannot be used on instance of type %0" - id: could_not_use_enum_element_on_instance - msg: >- - enum case %0 cannot be used as an instance member + msg: "enum case %0 cannot be used as an instance member" - id: could_not_use_type_member_on_protocol_metatype - msg: >- - static member %1 cannot be used on protocol metatype %0 + msg: "static member %1 cannot be used on protocol metatype %0" - id: could_not_use_instance_member_on_type - msg: >- - instance member %1%select{| of type %2}3 - cannot be used on%select{| instance of nested}3 type %0 + msg: "instance member %1%select{| of type %2}3 cannot be used on%select{| instance of nested}3 type %0" - id: could_not_use_member_on_existential - msg: >- - member %1 cannot be used on value of protocol type %0; use a generic - constraint instead + msg: "member %1 cannot be used on value of protocol type %0; use a generic constraint instead" - id: candidate_inaccessible - msg: >- - %0 is inaccessible due to - '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level + msg: "%0 is inaccessible due to '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level" - id: note_candidate_inaccessible - msg: >- - %0 is inaccessible due to - '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level + msg: "%0 is inaccessible due to '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level" - id: init_candidate_inaccessible - msg: >- - %0 initializer is inaccessible due to - '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level + msg: "%0 initializer is inaccessible due to '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level" - id: cannot_pass_rvalue_mutating_subelement - msg: >- - cannot use mutating member on immutable value: %0 + msg: "cannot use mutating member on immutable value: %0" - id: cannot_pass_rvalue_mutating - msg: >- - cannot use mutating member on immutable value of type %0 + msg: "cannot use mutating member on immutable value of type %0" - id: cannot_pass_rvalue_mutating_getter_subelement - msg: >- - cannot use mutating getter on immutable value: %0 + msg: "cannot use mutating getter on immutable value: %0" - id: cannot_pass_rvalue_mutating_getter - msg: >- - cannot use mutating getter on immutable value of type %0 + msg: "cannot use mutating getter on immutable value of type %0" - id: expression_too_complex - msg: >- - the compiler is unable to type-check this expression in reasonable time; - try breaking up the expression into distinct sub-expressions + msg: "the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions" - id: value_type_comparison_with_nil_illegal_did_you_mean - msg: >- - value of type %0 cannot be compared by reference; did you mean to compare - by value? + msg: "value of type %0 cannot be compared by reference; did you mean to compare by value?" - id: value_type_comparison_with_nil_illegal - msg: >- - type %0 is not optional, value can never be nil + msg: "type %0 is not optional, value can never be nil" - id: cannot_match_expr_pattern_with_value - msg: >- - expression pattern of type %0 cannot match values of type %1 + msg: "expression pattern of type %0 cannot match values of type %1" - id: cannot_match_expr_tuple_pattern_with_nontuple_value - msg: >- - tuple pattern cannot match values of non-tuple type %0 + msg: "tuple pattern cannot match values of non-tuple type %0" - id: cannot_match_unresolved_expr_pattern_with_value - msg: >- - pattern cannot match values of type %0 + msg: "pattern cannot match values of type %0" - id: cannot_reference_compare_types - msg: >- - cannot check reference equality of functions; operands here have types %1 - and %2 + msg: "cannot check reference equality of functions; operands here have types %1 and %2" - id: cannot_apply_binop_to_args - msg: >- - binary operator '%0' cannot be applied to operands of type %1 and %2 + msg: "binary operator '%0' cannot be applied to operands of type %1 and %2" - id: cannot_apply_binop_to_same_args - msg: >- - binary operator '%0' cannot be applied to two %1 operands + msg: "binary operator '%0' cannot be applied to two %1 operands" - id: cannot_apply_unop_to_arg - msg: >- - unary operator '%0' cannot be applied to an operand of type %1 + msg: "unary operator '%0' cannot be applied to an operand of type %1" - id: cannot_apply_lvalue_unop_to_subelement - msg: >- - cannot pass immutable value to mutating operator: %0 + msg: "cannot pass immutable value to mutating operator: %0" - id: cannot_apply_lvalue_unop_to_rvalue - msg: >- - cannot pass immutable value of type %0 to mutating operator + msg: "cannot pass immutable value of type %0 to mutating operator" - id: cannot_apply_lvalue_binop_to_subelement - msg: >- - left side of mutating operator isn't mutable: %0 + msg: "left side of mutating operator isn't mutable: %0" - id: cannot_apply_lvalue_binop_to_rvalue - msg: >- - left side of mutating operator has immutable type %0 + msg: "left side of mutating operator has immutable type %0" - id: cannot_subscript_base - msg: >- - cannot subscript a value of type %0 + msg: "cannot subscript a value of type %0" - id: cannot_subscript_ambiguous_base - msg: >- - cannot subscript a value of incorrect or ambiguous type + msg: "cannot subscript a value of incorrect or ambiguous type" - id: cannot_subscript_nil_literal - msg: >- - cannot subscript a nil literal value + msg: "cannot subscript a nil literal value" - id: conditional_cast_from_nil - msg: >- - nil literal cannot be the source of a conditional cast + msg: "nil literal cannot be the source of a conditional cast" - id: cannot_pass_rvalue_inout_subelement - msg: >- - cannot pass immutable value as inout argument: %0 + msg: "cannot pass immutable value as inout argument: %0" - id: cannot_pass_rvalue_inout_converted - msg: >- - inout argument could be set to a value with a type other than %0; use a - value declared as type %1 instead + msg: "inout argument could be set to a value with a type other than %0; use a value declared as type %1 instead" - id: inout_change_var_type_if_possible - msg: >- - change variable type to %1 if it doesn't need to be declared as %0 + msg: "change variable type to %1 if it doesn't need to be declared as %0" - id: cannot_pass_rvalue_inout - msg: >- - cannot pass immutable value of type %0 as inout argument + msg: "cannot pass immutable value of type %0 as inout argument" - id: cannot_provide_default_value_inout - msg: >- - cannot provide default value to inout parameter %0 + msg: "cannot provide default value to inout parameter %0" - id: cannot_call_with_params - msg: >- - cannot invoke %select{|initializer for type }2'%0' with an argument list - of type '%1' + msg: "cannot invoke %select{|initializer for type }2'%0' with an argument list of type '%1'" - id: cannot_call_non_function_value - msg: >- - cannot call value of non-function type %0 + msg: "cannot call value of non-function type %0" - id: no_candidates_match_result_type - msg: >- - no '%0' candidates produce the expected contextual result type %1 + msg: "no '%0' candidates produce the expected contextual result type %1" - id: no_candidates_match_argument_type - msg: >- - no '%0' candidates produce the expected type %1 for parameter #%2 + msg: "no '%0' candidates produce the expected type %1 for parameter #%2" - id: cannot_infer_closure_parameter_type - msg: >- - unable to infer type of a closure parameter %0 in the current context + msg: "unable to infer type of a closure parameter %0 in the current context" - id: cannot_infer_closure_type - msg: >- - unable to infer closure type in the current context + msg: "unable to infer closure type in the current context" - id: cannot_infer_closure_result_type - msg: >- - unable to infer%select{ complex|}0 closure return type; add explicit type - to disambiguate + msg: "unable to infer%select{ complex|}0 closure return type; add explicit type to disambiguate" - id: incorrect_explicit_closure_result - msg: >- - declared closure result %0 is incompatible with contextual type %1 + msg: "declared closure result %0 is incompatible with contextual type %1" - id: suggest_expected_match - msg: >- - %select{expected an argument list|produces result}0 of type '%1' + msg: "%select{expected an argument list|produces result}0 of type '%1'" - id: suggest_partial_overloads - msg: >- - overloads for '%1' exist with these %select{partially matching parameter - lists|result types}0: %2 + msg: "overloads for '%1' exist with these %select{partially matching parameter lists|result types}0: %2" - id: no_binary_op_overload_for_enum_with_payload - msg: >- - binary operator '%0' cannot be synthesized for enums with associated - values + msg: "binary operator '%0' cannot be synthesized for enums with associated values" - id: cannot_convert_initializer_value - msg: >- - cannot convert value of type %0 to specified type %1 + msg: "cannot convert value of type %0 to specified type %1" - id: cannot_convert_initializer_value_protocol - msg: >- - value of type %0 does not conform to specified type %1 + msg: "value of type %0 does not conform to specified type %1" - id: cannot_convert_initializer_value_anyobject - msg: >- - value of type %0 expected to be instance of class or class-constrained - type + msg: "value of type %0 expected to be instance of class or class-constrained type" - id: cannot_convert_initializer_value_nil - msg: >- - 'nil' cannot initialize specified type %0 + msg: "'nil' cannot initialize specified type %0" - id: cannot_convert_to_return_type - msg: >- - cannot convert return expression of type %0 to return type %1 + msg: "cannot convert return expression of type %0 to return type %1" - id: cannot_convert_to_return_type_protocol - msg: >- - return expression of type %0 does not conform to %1 + msg: "return expression of type %0 does not conform to %1" - id: cannot_convert_return_type_to_anyobject - msg: >- - return expression of type %0 expected to be an instance of a class or - class-constrained type + msg: "return expression of type %0 expected to be an instance of a class or class-constrained type" - id: cannot_convert_to_return_type_nil - msg: >- - 'nil' is incompatible with return type %0 + msg: "'nil' is incompatible with return type %0" - id: cannot_convert_thrown_type - msg: >- - thrown expression type %0 does not conform to 'Error' + msg: "thrown expression type %0 does not conform to 'Error'" - id: cannot_throw_error_code - msg: >- - thrown error code type %0 does not conform to 'Error'; construct an %1 - instance + msg: "thrown error code type %0 does not conform to 'Error'; construct an %1 instance" - id: bad_yield_count - msg: >- - expected %0 yield value(s) + msg: "expected %0 yield value(s)" - id: cannot_throw_nil - msg: >- - cannot infer concrete Error for thrown 'nil' value + msg: "cannot infer concrete Error for thrown 'nil' value" - id: cannot_convert_raw_initializer_value - msg: >- - cannot convert value of type %0 to raw type %1 + msg: "cannot convert value of type %0 to raw type %1" - id: cannot_convert_raw_initializer_value_nil - msg: >- - cannot convert 'nil' to raw type %0 + msg: "cannot convert 'nil' to raw type %0" - id: cannot_convert_default_arg_value - msg: >- - default argument value of type %0 cannot be converted to type %1 + msg: "default argument value of type %0 cannot be converted to type %1" - id: cannot_convert_default_arg_value_protocol - msg: >- - default argument value of type %0 does not conform to %1 + msg: "default argument value of type %0 does not conform to %1" - id: cannot_convert_default_arg_value_nil - msg: >- - nil default argument value cannot be converted to type %0 + msg: "nil default argument value cannot be converted to type %0" - id: cannot_convert_argument_value - msg: >- - cannot convert value of type %0 to expected argument type %1 + msg: "cannot convert value of type %0 to expected argument type %1" - id: candidate_has_invalid_argument_at_position - msg: >- - candidate expects %select{|in-out }2value of type %0 for parameter #%1 + msg: "candidate expects %select{|in-out }2value of type %0 for parameter #%1" - id: cannot_convert_array_to_variadic - msg: >- - cannot pass array of type %0 as variadic arguments of type %1 + msg: "cannot pass array of type %0 as variadic arguments of type %1" - id: candidate_would_match_array_to_variadic - msg: >- - candidate would match if array elements were passed as variadic arguments - of type %0 + msg: "candidate would match if array elements were passed as variadic arguments of type %0" - id: suggest_pass_elements_directly - msg: >- - remove brackets to pass array elements directly + msg: "remove brackets to pass array elements directly" - id: cannot_convert_argument_value_generic - msg: >- - cannot convert value of type %0 (%1) to expected argument type %2 (%3) + msg: "cannot convert value of type %0 (%1) to expected argument type %2 (%3)" - id: conflicting_arguments_for_generic_parameter - msg: >- - conflicting arguments to generic parameter %0 (%1) + msg: "conflicting arguments to generic parameter %0 (%1)" - id: cannot_pass_type_to_non_ephemeral - msg: >- - cannot pass %0 to parameter; argument %1 must be a pointer that outlives - the call%select{| to %3}2 + msg: "cannot pass %0 to parameter; argument %1 must be a pointer that outlives the call%select{| to %3}2" - id: cannot_pass_type_to_non_ephemeral_warning - msg: >- - passing %0 to parameter, but argument %1 should be a pointer that - outlives the call%select{| to %3}2 + msg: "passing %0 to parameter, but argument %1 should be a pointer that outlives the call%select{| to %3}2" - id: cannot_use_inout_non_ephemeral - msg: >- - cannot use inout expression here; argument %0 must be a pointer that - outlives the call%select{| to %2}1 + msg: "cannot use inout expression here; argument %0 must be a pointer that outlives the call%select{| to %2}1" - id: cannot_use_inout_non_ephemeral_warning - msg: >- - inout expression creates a temporary pointer, but argument %0 should be a - pointer that outlives the call%select{| to %2}1 + msg: "inout expression creates a temporary pointer, but argument %0 should be a pointer that outlives the call%select{| to %2}1" - id: cannot_construct_dangling_pointer - msg: >- - initialization of %0 results in a dangling %select{|buffer }1pointer + msg: "initialization of %0 results in a dangling %select{|buffer }1pointer" - id: cannot_construct_dangling_pointer_warning - msg: >- - initialization of %0 results in a dangling %select{|buffer }1pointer + msg: "initialization of %0 results in a dangling %select{|buffer }1pointer" - id: ephemeral_pointer_argument_conversion_note - msg: >- - implicit argument conversion from %0 to %1 produces a pointer valid only - for the duration of the call%select{| to %3}2 + msg: "implicit argument conversion from %0 to %1 produces a pointer valid only for the duration of the call%select{| to %3}2" - id: ephemeral_use_with_unsafe_pointer - msg: >- - use 'withUnsafe%select{Bytes|MutableBytes|Pointer|MutablePointer}0' in - order to explicitly convert argument to %select{buffer |buffer ||}0pointer - valid for a defined scope + msg: "use 'withUnsafe%select{Bytes|MutableBytes|Pointer|MutablePointer}0' in order to explicitly convert argument to %select{buffer |buffer ||}0pointer valid for a defined scope" - id: ephemeral_use_string_with_c_string - msg: >- - use the 'withCString' method on String in order to explicitly convert - argument to pointer valid for a defined scope + msg: "use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope" - id: ephemeral_use_array_with_unsafe_buffer - msg: >- - use the - 'withUnsafe%select{Bytes|MutableBytes|BufferPointer|MutableBufferPointer}0' - method on Array in order to explicitly convert argument to buffer pointer valid - for a defined scope + msg: "use the 'withUnsafe%select{Bytes|MutableBytes|BufferPointer|MutableBufferPointer}0' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope" - id: candidate_performs_illegal_ephemeral_conv - msg: >- - candidate expects pointer that outlives the call for parameter #%0 + msg: "candidate expects pointer that outlives the call for parameter #%0" - id: cannot_convert_argument_value_protocol - msg: >- - argument type %0 does not conform to expected type %1 + msg: "argument type %0 does not conform to expected type %1" - id: cannot_convert_argument_value_anyobject - msg: >- - argument type %0 expected to be an instance of a class or - class-constrained type + msg: "argument type %0 expected to be an instance of a class or class-constrained type" - id: cannot_convert_argument_value_nil - msg: >- - 'nil' is not compatible with expected argument type %0 + msg: "'nil' is not compatible with expected argument type %0" - id: cannot_convert_condition_value - msg: >- - cannot convert value of type %0 to expected condition type %1 + msg: "cannot convert value of type %0 to expected condition type %1" - id: cannot_convert_condition_value_nil - msg: >- - 'nil' is not compatible with expected condition type %0 + msg: "'nil' is not compatible with expected condition type %0" - id: cannot_yield_rvalue_by_reference_same_type - msg: >- - cannot yield immutable value of type %0 as an inout yield + msg: "cannot yield immutable value of type %0 as an inout yield" - id: cannot_yield_rvalue_by_reference - msg: >- - cannot yield immutable value of type %0 as an inout yield of type %1 + msg: "cannot yield immutable value of type %0 as an inout yield of type %1" - id: cannot_yield_wrong_type_by_reference - msg: >- - cannot yield reference to storage of type %0 as an inout yield of type %1 + msg: "cannot yield reference to storage of type %0 as an inout yield of type %1" - id: cannot_convert_yield_value - msg: >- - cannot convert value of type %0 to expected yield type %1 + msg: "cannot convert value of type %0 to expected yield type %1" - id: cannot_convert_yield_value_protocol - msg: >- - yielded type %0 does not conform to expected type %1 + msg: "yielded type %0 does not conform to expected type %1" - id: cannot_convert_yield_value_nil - msg: >- - nil is not compatible with expected yield type %0 + msg: "nil is not compatible with expected yield type %0" - id: cannot_convert_closure_result - msg: >- - cannot convert value of type %0 to closure result type %1 + msg: "cannot convert value of type %0 to closure result type %1" - id: cannot_convert_closure_result_protocol - msg: >- - result value of type %0 does not conform to closure result type %1 + msg: "result value of type %0 does not conform to closure result type %1" - id: cannot_convert_closure_result_nil - msg: >- - 'nil' is not compatible with closure result type %0 + msg: "'nil' is not compatible with closure result type %0" - id: cannot_convert_parent_type - msg: >- - cannot convert parent type %0 to expected type %1 + msg: "cannot convert parent type %0 to expected type %1" - id: generic_argument_mismatch - msg: >- - arguments to generic parameter %0 (%1 and %2) are expected to be equal + msg: "arguments to generic parameter %0 (%1 and %2) are expected to be equal" - id: destructor_not_accessible - msg: >- - deinitializers cannot be accessed + msg: "deinitializers cannot be accessed" - id: cannot_convert_array_element - msg: >- - cannot convert value of type %0 to expected element type %1 + msg: "cannot convert value of type %0 to expected element type %1" - id: cannot_convert_array_element_protocol - msg: >- - value of type %0 does not conform to expected element type %1 + msg: "value of type %0 does not conform to expected element type %1" - id: cannot_convert_array_element_nil - msg: >- - 'nil' is not compatible with expected element type %0 + msg: "'nil' is not compatible with expected element type %0" - id: cannot_convert_dict_key - msg: >- - cannot convert value of type %0 to expected dictionary key type %1 + msg: "cannot convert value of type %0 to expected dictionary key type %1" - id: cannot_convert_dict_key_protocol - msg: >- - value of type %0 does not conform to expected dictionary key type %1 + msg: "value of type %0 does not conform to expected dictionary key type %1" - id: cannot_convert_dict_key_nil - msg: >- - 'nil' is not compatible with expected dictionary key type %0 + msg: "'nil' is not compatible with expected dictionary key type %0" - id: cannot_convert_dict_value - msg: >- - cannot convert value of type %0 to expected dictionary value type %1 + msg: "cannot convert value of type %0 to expected dictionary value type %1" - id: cannot_convert_dict_value_protocol - msg: >- - value of type %0 does not conform to expected dictionary value type %1 + msg: "value of type %0 does not conform to expected dictionary value type %1" - id: cannot_convert_dict_value_nil - msg: >- - 'nil' is not compatible with expected dictionary value type %0 + msg: "'nil' is not compatible with expected dictionary value type %0" - id: cannot_convert_coerce - msg: >- - cannot convert value of type %0 to type %1 in coercion + msg: "cannot convert value of type %0 to type %1 in coercion" - id: cannot_convert_coerce_protocol - msg: >- - value of type %0 does not conform to %1 in coercion + msg: "value of type %0 does not conform to %1 in coercion" - id: cannot_convert_coerce_nil - msg: >- - 'nil' is not compatible with type %0 in coercion + msg: "'nil' is not compatible with type %0 in coercion" - id: cannot_convert_assign - msg: >- - cannot assign value of type %0 to type %1 + msg: "cannot assign value of type %0 to type %1" - id: assign_protocol_conformance_fix_it - msg: >- - add missing conformance to %0 to %1 %2 + msg: "add missing conformance to %0 to %1 %2" - id: cannot_convert_assign_protocol - msg: >- - value of type %0 does not conform to %1 in assignment + msg: "value of type %0 does not conform to %1 in assignment" - id: cannot_convert_assign_anyobject - msg: >- - value of type %0 expected to be an instance of a class or - class-constrained type in assignment + msg: "value of type %0 expected to be an instance of a class or class-constrained type in assignment" - id: cannot_convert_assign_nil - msg: >- - 'nil' cannot be assigned to type %0 + msg: "'nil' cannot be assigned to type %0" - id: cannot_convert_subscript_assign - msg: >- - cannot assign value of type %0 to subscript of type %1 + msg: "cannot assign value of type %0 to subscript of type %1" - id: cannot_convert_subscript_assign_protocol - msg: >- - value of type %0 does not conform to %1 in subscript assignment + msg: "value of type %0 does not conform to %1 in subscript assignment" - id: cannot_convert_subscript_assign_nil - msg: >- - 'nil' cannot be assigned to subscript of type %0 + msg: "'nil' cannot be assigned to subscript of type %0" - id: cannot_convert_candidate_result_to_contextual_type - msg: >- - %0 produces %1, not the expected contextual result type %2 + msg: "%0 produces %1, not the expected contextual result type %2" - id: cannot_convert_sequence_element_value - msg: >- - cannot convert sequence element type %0 to expected type %1 + msg: "cannot convert sequence element type %0 to expected type %1" - id: cannot_convert_sequence_element_protocol - msg: >- - sequence element type %0 does not conform to expected protocol %1 + msg: "sequence element type %0 does not conform to expected protocol %1" - id: throws_functiontype_mismatch - msg: >- - invalid conversion from throwing function of type %0 to non-throwing - function type %1 + msg: "invalid conversion from throwing function of type %0 to non-throwing function type %1" - id: expr_keypath_no_objc_runtime - msg: >- - '#keyPath' can only be used with the Objective-C runtime + msg: "'#keyPath' can only be used with the Objective-C runtime" - id: expression_unused_keypath_result - msg: >- - result of key path is unused + msg: "result of key path is unused" - id: expr_keypath_non_objc_property - msg: >- - argument of '#keyPath' refers to non-'@objc' property %0 + msg: "argument of '#keyPath' refers to non-'@objc' property %0" - id: expr_keypath_swift3_objc_inference - msg: >- - argument of '#keyPath' refers to property %0 in %1 that depends on - '@objc' inference deprecated in Swift 4 + msg: "argument of '#keyPath' refers to property %0 in %1 that depends on '@objc' inference deprecated in Swift 4" - id: expr_keypath_type_of_property - msg: >- - cannot refer to type member %0 within instance of type %1 + msg: "cannot refer to type member %0 within instance of type %1" - id: expr_keypath_generic_type - msg: >- - key path cannot refer to generic type %0 + msg: "key path cannot refer to generic type %0" - id: expr_keypath_not_property - msg: >- - %select{key path|dynamic key path member lookup}2 cannot refer to %0 %1 + msg: "%select{key path|dynamic key path member lookup}2 cannot refer to %0 %1" - id: expr_keypath_mutating_getter - msg: >- - %select{key path|dynamic key path member lookup}1 cannot refer to %0, - which has a mutating getter + msg: "%select{key path|dynamic key path member lookup}1 cannot refer to %0, which has a mutating getter" - id: expr_keypath_static_member - msg: >- - %select{key path|dynamic key path member lookup}1 cannot refer to static - member %0 + msg: "%select{key path|dynamic key path member lookup}1 cannot refer to static member %0" - id: expr_keypath_enum_case - msg: >- - %select{key path|dynamic key path member lookup}1 cannot refer to enum - case %0 + msg: "%select{key path|dynamic key path member lookup}1 cannot refer to enum case %0" - id: expr_keypath_empty - msg: >- - empty key path does not refer to a property + msg: "empty key path does not refer to a property" - id: expr_unsupported_objc_key_path_component - msg: >- - an Objective-C key path cannot contain - %select{BAD|subscript|BAD|BAD|optional-forcing|optional-chaining|BAD} - components + msg: "an Objective-C key path cannot contain %select{BAD|subscript|BAD|BAD|optional-forcing|optional-chaining|BAD} components" - id: expr_unsupported_objc_key_path_compound_name - msg: >- - an Objective-C key path cannot reference a declaration with a compound name + msg: "an Objective-C key path cannot reference a declaration with a compound name" - id: expr_keypath_no_keypath_type - msg: >- - broken standard library: no 'KeyPath' type found + msg: "broken standard library: no 'KeyPath' type found" - id: expr_swift_keypath_invalid_component - msg: >- - invalid component of Swift key path + msg: "invalid component of Swift key path" - id: expr_swift_keypath_not_starting_with_type - msg: >- - a Swift key path must begin with a type + msg: "a Swift key path must begin with a type" - id: expr_swift_keypath_not_starting_with_dot - msg: >- - a Swift key path with contextual root must begin with a leading dot + msg: "a Swift key path with contextual root must begin with a leading dot" - id: expr_smart_keypath_value_covert_to_contextual_type - msg: >- - key path value type %0 cannot be converted to contextual type %1 + msg: "key path value type %0 cannot be converted to contextual type %1" - id: expr_swift_keypath_empty - msg: >- - key path must have at least one component + msg: "key path must have at least one component" - id: expr_string_interpolation_outside_string - msg: >- - string interpolation can only appear inside a string literal + msg: "string interpolation can only appear inside a string literal" - id: expr_keypath_subscript_index_not_hashable - msg: >- - subscript index of type %0 in a key path must be Hashable + msg: "subscript index of type %0 in a key path must be Hashable" - id: expr_smart_keypath_application_type_mismatch - msg: >- - key path of type %0 cannot be applied to a base of type %1 + msg: "key path of type %0 cannot be applied to a base of type %1" - id: expr_keypath_root_type_mismatch - msg: >- - key path with root type %0 cannot be applied to a base of type %1 + msg: "key path with root type %0 cannot be applied to a base of type %1" - id: expr_swift_keypath_anyobject_root - msg: >- - the root type of a Swift key path cannot be 'AnyObject' + msg: "the root type of a Swift key path cannot be 'AnyObject'" - id: expr_keypath_multiparam_func_conversion - msg: >- - cannot convert key path into a multi-argument function type %0 + msg: "cannot convert key path into a multi-argument function type %0" - id: expr_deprecated_writable_keypath - msg: >- - forming a writable keypath to property %0 that is read-only in this - context is deprecated and will be removed in a future release + msg: "forming a writable keypath to property %0 that is read-only in this context is deprecated and will be removed in a future release" - id: expr_selector_no_objc_runtime - msg: >- - '#selector' can only be used with the Objective-C runtime + msg: "'#selector' can only be used with the Objective-C runtime" - id: expr_selector_module_missing - msg: >- - import the 'ObjectiveC' module to use '#selector' + msg: "import the 'ObjectiveC' module to use '#selector'" - id: expr_selector_no_declaration - msg: >- - argument of '#selector' does not refer to an '@objc' method, property, or - initializer + msg: "argument of '#selector' does not refer to an '@objc' method, property, or initializer" - id: expr_selector_not_method - msg: >- - argument of '#selector' cannot refer to %select{local|global}0 function %1 + msg: "argument of '#selector' cannot refer to %select{local|global}0 function %1" - id: expr_selector_expected_property - msg: >- - cannot reference %1 %2 as a property; remove '%select{getter|setter}0:' + msg: "cannot reference %1 %2 as a property; remove '%select{getter|setter}0:'" - id: expr_selector_not_property - msg: >- - argument of '#selector' cannot refer to %select{variable|parameter}0 %1 + msg: "argument of '#selector' cannot refer to %select{variable|parameter}0 %1" - id: expr_selector_expected_method - msg: >- - use 'getter:'%select{| or 'setter:'}0 to refer to the Objective-C - getter%select{| or setter}0 of property %1%select{|, respectively}0 + msg: "use 'getter:'%select{| or 'setter:'}0 to refer to the Objective-C getter%select{| or setter}0 of property %1%select{|, respectively}0" - id: expr_selector_add_modifier - msg: >- - add '%select{getter|setter}0:' to reference the Objective-C - %select{getter|setter}0 for %1 + msg: "add '%select{getter|setter}0:' to reference the Objective-C %select{getter|setter}0 for %1" - id: expr_selector_property_not_settable - msg: >- - argument of '#selector(setter:)' refers to non-settable %0 %1 + msg: "argument of '#selector(setter:)' refers to non-settable %0 %1" - id: expr_selector_property_setter_inaccessible - msg: >- - setter of %0 %1 is inaccessible + msg: "setter of %0 %1 is inaccessible" - id: expr_selector_cannot_be_used - msg: >- - cannot use %0 as a selector because protocol %1 is not exposed to - Objective-C + msg: "cannot use %0 as a selector because protocol %1 is not exposed to Objective-C" - id: expr_selector_not_objc - msg: >- - argument of '#selector' refers to %0 %1 that is not exposed to Objective-C + msg: "argument of '#selector' refers to %0 %1 that is not exposed to Objective-C" - id: make_decl_objc - msg: >- - add '@objc' to expose this %0 to Objective-C + msg: "add '@objc' to expose this %0 to Objective-C" - id: expr_selector_swift3_objc_inference - msg: >- - argument of '#selector' refers to %0 %1 in %2 that depends on '@objc' - inference deprecated in Swift 4 + msg: "argument of '#selector' refers to %0 %1 in %2 that depends on '@objc' inference deprecated in Swift 4" - id: selector_literal_invalid - msg: >- - string literal is not a valid Objective-C selector + msg: "string literal is not a valid Objective-C selector" - id: selector_literal_undeclared - msg: >- - no method declared with Objective-C selector %0 + msg: "no method declared with Objective-C selector %0" - id: selector_literal_deprecated - msg: >- - use of string literal for Objective-C selectors is deprecated; use - '#selector' or explicitly construct a 'Selector' + msg: "use of string literal for Objective-C selectors is deprecated; use '#selector' or explicitly construct a 'Selector'" - id: selector_literal_deprecated_suggest - msg: >- - use of string literal for Objective-C selectors is deprecated; use - '#selector' instead + msg: "use of string literal for Objective-C selectors is deprecated; use '#selector' instead" - id: selector_construction_suggest - msg: >- - use '#selector' instead of explicitly constructing a 'Selector' + msg: "use '#selector' instead of explicitly constructing a 'Selector'" - id: selector_construction_suppress_warning - msg: >- - wrap the selector name in parentheses to suppress this warning + msg: "wrap the selector name in parentheses to suppress this warning" - id: cannot_return_value_from_void_func - msg: >- - unexpected non-void return value in void function + msg: "unexpected non-void return value in void function" - id: add_return_type_note - msg: >- - did you mean to add a return type? + msg: "did you mean to add a return type?" - id: sema_no_import - msg: >- - no such module '%0' + msg: "no such module '%0'" - id: sema_no_import_target - msg: >- - could not find module '%0' for target '%1'; found: %2 + msg: "could not find module '%0' for target '%1'; found: %2" - id: sema_no_import_repl - msg: >- - no such module '%0' + msg: "no such module '%0'" - id: sema_no_import_no_sdk - msg: >- - did you forget to set an SDK using -sdk or SDKROOT? + msg: "did you forget to set an SDK using -sdk or SDKROOT?" - id: sema_no_import_no_sdk_xcrun - msg: >- - use "xcrun swiftc" to select the default macOS SDK installed with Xcode + msg: "use \"xcrun swiftc\" to select the default macOS SDK installed with Xcode" - id: sema_import_current_module - msg: >- - this file is part of module %0; ignoring import + msg: "this file is part of module %0; ignoring import" - id: sema_import_current_module_with_file - msg: >- - file '%0' is part of module %1; ignoring import + msg: "file '%0' is part of module %1; ignoring import" - id: sema_opening_import - msg: >- - opening import file for module %0: %1 + msg: "opening import file for module %0: %1" - id: serialization_load_failed - msg: >- - failed to load module '%0' + msg: "failed to load module '%0'" - id: module_interface_build_failed - msg: >- - failed to build module '%0' from its module interface; %select{the - compiler that produced it, '%2', may have used features that aren't - supported by this compiler, '%3'|it may have been damaged - or it may have triggered a bug in the Swift compiler when it was produced}1 + msg: "failed to build module '%0' from its module interface; %select{the compiler that produced it, '%2', may have used features that aren't supported by this compiler, '%3'|it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced}1" - id: serialization_malformed_module - msg: >- - malformed compiled module: %0 + msg: "malformed compiled module: %0" - id: serialization_module_too_new - msg: >- - compiled module was created by a newer version of the compiler: %0 + msg: "compiled module was created by a newer version of the compiler: %0" - id: serialization_module_language_version_mismatch - msg: >- - module compiled with Swift %0 cannot be imported by the Swift %1 - compiler: %2 + msg: "module compiled with Swift %0 cannot be imported by the Swift %1 compiler: %2" - id: serialization_module_too_old - msg: >- - compiled module was created by an older version of the compiler; rebuild - %0 and try again: %1 + msg: "compiled module was created by an older version of the compiler; rebuild %0 and try again: %1" - id: serialization_missing_single_dependency - msg: >- - missing required module '%0' + msg: "missing required module '%0'" - id: serialization_missing_dependencies - msg: >- - missing required modules: %0 + msg: "missing required modules: %0" - id: serialization_circular_dependency - msg: >- - circular dependency between modules '%0' and %1 + msg: "circular dependency between modules '%0' and %1" - id: serialization_missing_underlying_module - msg: >- - cannot load underlying module for %0 + msg: "cannot load underlying module for %0" - id: serialization_name_mismatch - msg: >- - cannot load module '%0' as '%1' + msg: "cannot load module '%0' as '%1'" - id: serialization_name_mismatch_repl - msg: >- - cannot load module '%0' as '%1' + msg: "cannot load module '%0' as '%1'" - id: serialization_target_incompatible - msg: >- - module %0 was created for incompatible target %1: %2 + msg: "module %0 was created for incompatible target %1: %2" - id: serialization_target_incompatible_repl - msg: >- - module %0 was created for incompatible target %1: %2 + msg: "module %0 was created for incompatible target %1: %2" - id: serialization_target_too_new - msg: >- - compiling for %0 %1, but module %2 has a minimum deployment target of %0 - %3: %4 + msg: "compiling for %0 %1, but module %2 has a minimum deployment target of %0 %3: %4" - id: serialization_target_too_new_repl - msg: >- - compiling for %0 %1, but module %2 has a minimum deployment target of %0 - %3: %4 + msg: "compiling for %0 %1, but module %2 has a minimum deployment target of %0 %3: %4" - id: serialization_fatal - msg: >- - fatal error encountered while reading from module '%0'; please file a bug - report with your project and the crash log + msg: "fatal error encountered while reading from module '%0'; please file a bug report with your project and the crash log" - id: serialization_misc_version - msg: >- - module '%0' full misc version is '%1' + msg: "module '%0' full misc version is '%1'" - id: serialization_compatibility_version_mismatch - msg: >- - compiling as Swift %0, with '%1' built as Swift %2 (this is supported but - may expose additional compiler issues) + msg: "compiling as Swift %0, with '%1' built as Swift %2 (this is supported but may expose additional compiler issues)" - id: reserved_member_name - msg: >- - type member must not be named %0, since it would conflict with the - 'foo.%1' expression + msg: "type member must not be named %0, since it would conflict with the 'foo.%1' expression" - id: invalid_redecl - msg: >- - invalid redeclaration of %0 + msg: "invalid redeclaration of %0" - id: invalid_redecl_init - msg: >- - invalid redeclaration of synthesized %select{|memberwise }1%0 + msg: "invalid redeclaration of synthesized %select{|memberwise }1%0" - id: invalid_redecl_implicit - msg: >- - invalid redeclaration of synthesized %select{%0|implementation for - protocol requirement}1 %2 + msg: "invalid redeclaration of synthesized %select{%0|implementation for protocol requirement}1 %2" - id: invalid_redecl_swift5_warning - msg: >- - redeclaration of %0 is deprecated and will be an error in Swift 5 + msg: "redeclaration of %0 is deprecated and will be an error in Swift 5" - id: invalid_redecl_prev - msg: >- - %0 previously declared here + msg: "%0 previously declared here" - id: invalid_redecl_implicit_wrapper - msg: >- - %0 synthesized for property wrapper %select{projected value|backing - storage}1 + msg: "%0 synthesized for property wrapper %select{projected value|backing storage}1" - id: ambiguous_type_base - msg: >- - %0 is ambiguous for type lookup in this context + msg: "%0 is ambiguous for type lookup in this context" - id: invalid_member_type - msg: >- - %0 is not a member type of %1 + msg: "%0 is not a member type of %1" - id: invalid_member_type_suggest - msg: >- - %0 does not have a member type named %1; did you mean %2? + msg: "%0 does not have a member type named %1; did you mean %2?" - id: invalid_member_reference - msg: >- - %0 %1 is not a member type of %2 + msg: "%0 %1 is not a member type of %2" - id: ambiguous_member_type - msg: >- - ambiguous type name %0 in %1 + msg: "ambiguous type name %0 in %1" - id: no_module_type - msg: >- - no type named %0 in module %1 + msg: "no type named %0 in module %1" - id: ambiguous_module_type - msg: >- - ambiguous type name %0 in module %1 + msg: "ambiguous type name %0 in module %1" - id: use_nonmatching_operator - msg: >- - %0 is not a %select{binary|prefix unary|postfix unary}1 operator + msg: "%0 is not a %select{binary|prefix unary|postfix unary}1 operator" - id: unsupported_recursion_in_associated_type_reference - msg: >- - unsupported recursion for reference to %select{associated type|type - alias}0 %1 of type %2 + msg: "unsupported recursion for reference to %select{associated type|type alias}0 %1 of type %2" - id: broken_associated_type_witness - msg: >- - reference to invalid %select{associated type|type alias}0 %1 of type %2 + msg: "reference to invalid %select{associated type|type alias}0 %1 of type %2" - id: unspaced_binary_operator_fixit - msg: >- - missing whitespace between %0 and %1 operators + msg: "missing whitespace between %0 and %1 operators" - id: unspaced_binary_operator - msg: >- - ambiguous missing whitespace between unary and binary operators + msg: "ambiguous missing whitespace between unary and binary operators" - id: unspaced_binary_operators_candidate - msg: >- - could be %select{binary|postfix}2 %0 and %select{prefix|binary}2 %1 + msg: "could be %select{binary|postfix}2 %0 and %select{prefix|binary}2 %1" - id: unspaced_unary_operator - msg: >- - unary operators must not be juxtaposed; parenthesize inner expression + msg: "unary operators must not be juxtaposed; parenthesize inner expression" - id: cannot_find_in_scope - msg: >- - cannot %select{find|find operator}1 %0 in scope + msg: "cannot %select{find|find operator}1 %0 in scope" - id: cannot_find_in_scope_corrected - msg: >- - cannot %select{find|find operator}1 %0 in scope; did you mean '%2'? + msg: "cannot %select{find|find operator}1 %0 in scope; did you mean '%2'?" - id: confusable_character - msg: >- - %select{identifier|operator}0 '%1' contains possibly confused characters; - did you mean to use '%2'? + msg: "%select{identifier|operator}0 '%1' contains possibly confused characters; did you mean to use '%2'?" + - id: single_confusable_character - msg: >- - %select{identifier|operator}0 '%1' (%2) looks similar to '%3' (%4); did you mean '%3' (%4)?" + msg: "%select{identifier|operator}0 '%1' (%2) looks similar to '%3' (%4); did you mean '%3' (%4)?" - id: cannot_find_type_in_scope - msg: >- - cannot find type %0 in scope + msg: "cannot find type %0 in scope" - id: cannot_find_type_in_scope_did_you_mean - msg: >- - cannot find type %0 in scope; did you mean to use '%1'? + msg: "cannot find type %0 in scope; did you mean to use '%1'?" - id: note_typo_candidate_implicit_member - msg: >- - did you mean the implicitly-synthesized %1 '%0'? + msg: "did you mean the implicitly-synthesized %1 '%0'?" - id: note_remapped_type - msg: >- - did you mean to use '%0'? + msg: "did you mean to use '%0'?" - id: note_module_as_type - msg: >- - cannot use module %0 as a type + msg: "cannot use module %0 as a type" - id: use_unknown_object_literal_protocol - msg: >- - cannot deduce protocol for %0 literal + msg: "cannot deduce protocol for %0 literal" - id: object_literal_default_type_missing - msg: >- - could not infer type of %0 literal + msg: "could not infer type of %0 literal" - id: object_literal_resolve_import - msg: >- - import %0 to use '%1' as the default %2 literal type + msg: "import %0 to use '%1' as the default %2 literal type" - id: use_local_before_declaration - msg: >- - use of local variable %0 before its declaration + msg: "use of local variable %0 before its declaration" - id: unsupported_existential_type - msg: >- - protocol %0 can only be used as a generic constraint because it has Self - or associated type requirements + msg: "protocol %0 can only be used as a generic constraint because it has Self or associated type requirements" - id: decl_does_not_exist_in_module - msg: >- - %select{%error|type|struct|class|enum|protocol|variable|function}0 %1 - does not exist in module %2 + msg: "%select{%error|type|struct|class|enum|protocol|variable|function}0 %1 does not exist in module %2" - id: imported_decl_is_wrong_kind - msg: >- - %0 was imported as '%1', but is %select{%error|a type|a struct|a class|an - enum|a protocol|a variable|a function}2 + msg: "%0 was imported as '%1', but is %select{%error|a type|a struct|a class|an enum|a protocol|a variable|a function}2" - id: imported_decl_is_wrong_kind_typealias - msg: >- - %0 %1 cannot be imported as '%2' + msg: "%0 %1 cannot be imported as '%2'" - id: ambiguous_decl_in_module - msg: >- - ambiguous name %0 in module %1 + msg: "ambiguous name %0 in module %1" - id: module_not_testable - msg: >- - module %0 was not compiled for testing + msg: "module %0 was not compiled for testing" - id: module_not_compiled_for_private_import - msg: >- - module %0 was not compiled for private import + msg: "module %0 was not compiled for private import" - id: import_implementation_cannot_be_exported - msg: >- - module %0 cannot be both exported and implementation-only + msg: "module %0 cannot be both exported and implementation-only" - id: module_not_compiled_with_library_evolution - msg: >- - module %0 was not compiled with library evolution support; using it means - binary compatibility for %1 can't be guaranteed + msg: "module %0 was not compiled with library evolution support; using it means binary compatibility for %1 can't be guaranteed" - id: cross_import_added - msg: >- - import of %0 and %1 triggered a cross-import of %2 + msg: "import of %0 and %1 triggered a cross-import of %2" - id: ambiguous_operator_decls - msg: >- - ambiguous operator declarations found for operator + msg: "ambiguous operator declarations found for operator" - id: found_this_operator_decl - msg: >- - found this matching operator declaration + msg: "found this matching operator declaration" - id: operator_redeclared - msg: >- - operator redeclared + msg: "operator redeclared" - id: previous_operator_decl - msg: >- - previous operator declaration here + msg: "previous operator declaration here" - id: declared_operator_without_operator_decl - msg: >- - operator implementation without matching operator declaration + msg: "operator implementation without matching operator declaration" - id: declared_unary_op_without_attribute - msg: >- - unary operator implementation must have a 'prefix' or 'postfix' modifier + msg: "unary operator implementation must have a 'prefix' or 'postfix' modifier" - id: unary_op_missing_prepos_attribute - msg: >- - %select{prefix|postfix}0 unary operator missing - '%select{prefix|postfix}0' modifier + msg: "%select{prefix|postfix}0 unary operator missing '%select{prefix|postfix}0' modifier" - id: unary_operator_declaration_here - msg: >- - %select{prefix|postfix}0 operator found here + msg: "%select{prefix|postfix}0 operator found here" - id: invalid_arg_count_for_operator - msg: >- - operators must have one or two arguments + msg: "operators must have one or two arguments" - id: operator_in_local_scope - msg: >- - operator functions can only be declared at global or in type scope + msg: "operator functions can only be declared at global or in type scope" - id: nonstatic_operator_in_nominal - msg: >- - operator %0 declared in type %1 must be 'static' + msg: "operator %0 declared in type %1 must be 'static'" - id: nonstatic_operator_in_extension - msg: >- - operator %0 declared in extension%select{| of %2}1 must be 'static' + msg: "operator %0 declared in extension%select{| of %2}1 must be 'static'" - id: nonfinal_operator_in_class - msg: >- - operator %0 declared in non-final class %1 must be 'final' + msg: "operator %0 declared in non-final class %1 must be 'final'" - id: operator_in_unrelated_type - msg: >- - member operator %2%select{| of protocol %0}1 must have at least one - argument of type %select{%0|'Self'}1 + msg: "member operator %2%select{| of protocol %0}1 must have at least one argument of type %select{%0|'Self'}1" - id: ambiguous_precedence_groups - msg: >- - multiple precedence groups found + msg: "multiple precedence groups found" - id: found_this_precedence_group - msg: >- - found this matching precedence group + msg: "found this matching precedence group" - id: unknown_precedence_group - msg: >- - unknown precedence group %0 + msg: "unknown precedence group %0" - id: precedence_group_cycle - msg: >- - cycle in '%select{lowerThan|higherThan}0' relation + msg: "cycle in '%select{lowerThan|higherThan}0' relation" - id: higher_than_precedence_group_cycle - msg: >- - cycle in higherThan relation: %0 + msg: "cycle in higherThan relation: %0" - id: precedence_group_lower_within_module - msg: >- - precedence group cannot be given lower precedence than group in same - module; make the other precedence group higher than this one instead + msg: "precedence group cannot be given lower precedence than group in same module; make the other precedence group higher than this one instead" - id: precedence_group_redeclared - msg: >- - precedence group redeclared + msg: "precedence group redeclared" - id: previous_precedence_group_decl - msg: >- - previous precedence group declaration here + msg: "previous precedence group declaration here" - id: circular_reference_through_precedence_group - msg: >- - through reference to precedence group %0 here + msg: "through reference to precedence group %0 here" - id: tuple_types_not_convertible_nelts - msg: >- - %0 is not convertible to %1, tuples have a different number of elements + msg: "%0 is not convertible to %1, tuples have a different number of elements" - id: tuple_types_not_convertible - msg: >- - tuple type %0 is not convertible to tuple type %1 + msg: "tuple type %0 is not convertible to tuple type %1" - id: invalid_force_unwrap - msg: >- - cannot force unwrap value of non-optional type %0 + msg: "cannot force unwrap value of non-optional type %0" - id: invalid_optional_chain - msg: >- - cannot use optional chaining on non-optional value of type %0 + msg: "cannot use optional chaining on non-optional value of type %0" - id: if_expr_cases_mismatch - msg: >- - result values in '? :' expression have mismatching types %0 and %1 + msg: "result values in '? :' expression have mismatching types %0 and %1" - id: did_not_call_function_value - msg: >- - function value was used as a property; add () to call it + msg: "function value was used as a property; add () to call it" - id: did_not_call_function - msg: >- - function %0 was used as a property; add () to call it + msg: "function %0 was used as a property; add () to call it" - id: did_not_call_method - msg: >- - method %0 was used as a property; add () to call it + msg: "method %0 was used as a property; add () to call it" - id: init_not_instance_member_use_assignment - msg: >- - 'init' is a member of the type; use assignment to initalize the value - instead + msg: "'init' is a member of the type; use assignment to initalize the value instead" - id: init_not_instance_member - msg: >- - 'init' is a member of the type; use 'type(of: ...)' to initialize a new - object of the same dynamic type + msg: "'init' is a member of the type; use 'type(of: ...)' to initialize a new object of the same dynamic type" - id: super_initializer_not_in_initializer - msg: >- - 'super.init' cannot be called outside of an initializer + msg: "'super.init' cannot be called outside of an initializer" - id: isa_is_always_true - msg: >- - '%0' test is always true + msg: "'%0' test is always true" - id: isa_is_foreign_check - msg: >- - 'is' test is always true because %0 is a Core Foundation type + msg: "'is' test is always true because %0 is a Core Foundation type" - id: conditional_downcast_coercion - msg: >- - conditional cast from %0 to %1 always succeeds + msg: "conditional cast from %0 to %1 always succeeds" - id: literal_conditional_downcast_to_coercion - msg: >- - conditional downcast from literal to %0 always fails; consider using 'as' - coercion + msg: "conditional downcast from literal to %0 always fails; consider using 'as' coercion" - id: forced_downcast_noop - msg: >- - forced cast of %0 to same type has no effect + msg: "forced cast of %0 to same type has no effect" - id: forced_downcast_coercion - msg: >- - forced cast from %0 to %1 always succeeds; did you mean to use 'as'? + msg: "forced cast from %0 to %1 always succeeds; did you mean to use 'as'?" - id: downcast_same_type - msg: >- - forced cast from %0 to %1 %select{only unwraps optionals|only unwraps and - bridges}3; did you mean to use '%2'%select{| with 'as'}3? + msg: "forced cast from %0 to %1 %select{only unwraps optionals|only unwraps and bridges}3; did you mean to use '%2'%select{| with 'as'}3?" - id: conditional_downcast_same_type - msg: >- - conditional downcast from %0 to %1 %select{does nothing|is equivalent to - an implicit conversion to an optional %1|is a bridging conversion; - did you mean to use 'as'?}2 + msg: "conditional downcast from %0 to %1 %select{does nothing|is equivalent to an implicit conversion to an optional %1|is a bridging conversion; did you mean to use 'as'?}2" - id: is_expr_same_type - msg: >- - checking a value with optional type %0 against dynamic type %1 succeeds - whenever the value is non-nil; did you mean to use '!= nil'? + msg: "checking a value with optional type %0 against dynamic type %1 succeeds whenever the value is non-nil; did you mean to use '!= nil'?" - id: downcast_to_unrelated - msg: >- - cast from %0 to unrelated type %1 always fails + msg: "cast from %0 to unrelated type %1 always fails" - id: downcast_to_unrelated_fixit - msg: >- - did you mean to call %0 with '()'? + msg: "did you mean to call %0 with '()'?" - id: downcast_to_more_optional - msg: >- - cannot downcast from %0 to a more optional type %1 + msg: "cannot downcast from %0 to a more optional type %1" - id: optional_chain_noop - msg: >- - optional chain has no effect, expression already produces %0 + msg: "optional chain has no effect, expression already produces %0" - id: optional_chain_isnt_chaining - msg: >- - '?' must be followed by a call, member lookup, or subscript + msg: "'?' must be followed by a call, member lookup, or subscript" - id: pattern_in_expr - msg: >- - %0 cannot appear in an expression + msg: "%0 cannot appear in an expression" - id: note_call_to_operator - msg: >- - in call to operator %0 + msg: "in call to operator %0" - id: note_call_to_func - msg: >- - in call to function %0 + msg: "in call to function %0" - id: note_call_to_subscript - msg: >- - in call to %0 + msg: "in call to %0" - id: note_call_to_initializer - msg: >- - in call to initializer + msg: "in call to initializer" - id: note_init_parameter - msg: >- - in initialization of parameter %0 + msg: "in initialization of parameter %0" - id: missing_nullary_call - msg: >- - function produces expected type %0; did you mean to call it with '()'? + msg: "function produces expected type %0; did you mean to call it with '()'?" - id: optional_not_unwrapped - msg: >- - value of optional type %0 must be unwrapped to a value of type %1 + msg: "value of optional type %0 must be unwrapped to a value of type %1" - id: unwrap_with_default_value - msg: >- - coalesce using '??' to provide a default when the optional value contains - 'nil' + msg: "coalesce using '??' to provide a default when the optional value contains 'nil'" - id: unwrap_with_force_value - msg: >- - force-unwrap using '!' to abort execution if the optional value contains - 'nil' + msg: "force-unwrap using '!' to abort execution if the optional value contains 'nil'" - id: unwrap_iuo_initializer - msg: >- - value inferred to be type %0 when initialized with an implicitly - unwrapped value + msg: "value inferred to be type %0 when initialized with an implicitly unwrapped value" - id: unwrap_with_guard - msg: >- - short-circuit using 'guard' to exit this function early if the optional - value contains 'nil' + msg: "short-circuit using 'guard' to exit this function early if the optional value contains 'nil'" - id: optional_base_not_unwrapped - msg: >- - value of optional type %0 must be unwrapped to refer to member %1 of - wrapped base type %2 + msg: "value of optional type %0 must be unwrapped to refer to member %1 of wrapped base type %2" - id: optional_base_chain - msg: >- - chain the optional using '?' to access member %0 only for non-'nil' base - values + msg: "chain the optional using '?' to access member %0 only for non-'nil' base values" - id: optional_base_remove_optional_for_keypath_root - msg: >- - use unwrapped type %0 as key path root + msg: "use unwrapped type %0 as key path root" -- id: optional_keypath_application_base - msg: >- - use '?' to access key path subscript only for non-'nil' base values +- id: optional_keypath_application_base + msg: "use '?' to access key path subscript only for non-'nil' base values" - id: missing_unwrap_optional_try - msg: >- - value of optional type %0 not unwrapped; did you mean to use 'try!' or - chain with '?'? + msg: "value of optional type %0 not unwrapped; did you mean to use 'try!' or chain with '?'?" - id: missing_forced_downcast - msg: >- - %0 is not convertible to %1; did you mean to use 'as!' to force downcast? + msg: "%0 is not convertible to %1; did you mean to use 'as!' to force downcast?" - id: coercion_may_fail_warning - msg: >- - coercion from %0 to %1 may fail; use 'as?' or 'as!' instead + msg: "coercion from %0 to %1 may fail; use 'as?' or 'as!' instead" - id: missing_explicit_conversion - msg: >- - %0 is not implicitly convertible to %1; did you mean to use 'as' to - explicitly convert? + msg: "%0 is not implicitly convertible to %1; did you mean to use 'as' to explicitly convert?" - id: missing_address_of - msg: >- - passing value of type %0 to an inout parameter requires explicit '&' + msg: "passing value of type %0 to an inout parameter requires explicit '&'" - id: missing_address_of_yield - msg: >- - yielding mutable value of type %0 requires explicit '&' + msg: "yielding mutable value of type %0 requires explicit '&'" - id: extraneous_address_of - msg: >- - use of extraneous '&' + msg: "use of extraneous '&'" - id: extra_address_of - msg: >- - '&' used with non-inout argument of type %0 + msg: "'&' used with non-inout argument of type %0" - id: extra_address_of_unsafepointer - msg: >- - '&' is not allowed passing array value as %0 argument + msg: "'&' is not allowed passing array value as %0 argument" - id: cannot_pass_inout_arg_to_subscript - msg: >- - cannot pass an inout argument to a subscript; use - 'withUnsafeMutablePointer' to explicitly convert argument to a pointer + msg: "cannot pass an inout argument to a subscript; use 'withUnsafeMutablePointer' to explicitly convert argument to a pointer" - id: incorrect_property_wrapper_reference - msg: >- - cannot convert value %0 of type %1 to expected type %2, use - %select{wrapper|wrapped value}3 instead + msg: "cannot convert value %0 of type %1 to expected type %2, use %select{wrapper|wrapped value}3 instead" - id: incorrect_property_wrapper_reference_member - msg: >- - referencing %0 %1 requires %select{wrapper|wrapped value of type}2 %3 + msg: "referencing %0 %1 requires %select{wrapper|wrapped value of type}2 %3" - id: missing_init_on_metatype_initialization - msg: >- - initializing from a metatype value must reference 'init' explicitly + msg: "initializing from a metatype value must reference 'init' explicitly" - id: extra_argument_labels - msg: >- - extraneous argument label%select{|s}0 '%1' in %select{call|subscript}2 + msg: "extraneous argument label%select{|s}0 '%1' in %select{call|subscript}2" - id: missing_argument_labels - msg: >- - missing argument label%select{|s}0 '%1' in %select{call|subscript}2 + msg: "missing argument label%select{|s}0 '%1' in %select{call|subscript}2" - id: wrong_argument_labels - msg: >- - incorrect argument label%select{|s}0 in %select{call|subscript}3 (have - '%1', expected '%2') + msg: "incorrect argument label%select{|s}0 in %select{call|subscript}3 (have '%1', expected '%2')" - id: argument_out_of_order_named_named - msg: >- - argument %0 must precede argument %1 + msg: "argument %0 must precede argument %1" - id: argument_out_of_order_named_unnamed - msg: >- - argument %0 must precede unnamed argument #%1 + msg: "argument %0 must precede unnamed argument #%1" - id: argument_out_of_order_unnamed_named - msg: >- - unnamed argument #%0 must precede argument %1 + msg: "unnamed argument #%0 must precede argument %1" - id: argument_out_of_order_unnamed_unnamed - msg: >- - unnamed argument #%0 must precede unnamed argument #%1 + msg: "unnamed argument #%0 must precede unnamed argument #%1" - id: argument_out_of_order_binary_op - msg: >- - operator argument #%0 must precede operator argument #%1 + msg: "operator argument #%0 must precede operator argument #%1" - id: candidate_expected_different_labels - msg: >- - incorrect labels for candidate (have: '%0', expected: '%1') + msg: "incorrect labels for candidate (have: '%0', expected: '%1')" - id: member_shadows_function - msg: >- - use of %0 refers to %1 rather than %2 %3 + msg: "use of %0 refers to %1 rather than %2 %3" - id: member_shadows_global_function - msg: >- - use of %0 refers to %1 rather than %2 %3 in module %4 + msg: "use of %0 refers to %1 rather than %2 %3 in module %4" - id: instance_member_use_on_type - msg: >- - instance member %1 cannot be used on type %0; did you mean to use a value - of this type instead? + msg: "instance member %1 cannot be used on type %0; did you mean to use a value of this type instead?" - id: instance_member_in_initializer - msg: >- - cannot use instance member %0 within property initializer; property - initializers run before 'self' is available + msg: "cannot use instance member %0 within property initializer; property initializers run before 'self' is available" - id: instance_member_in_default_parameter - msg: >- - cannot use instance member %0 as a default parameter + msg: "cannot use instance member %0 as a default parameter" - id: missing_argument_named - msg: >- - missing argument for parameter %0 in call + msg: "missing argument for parameter %0 in call" - id: missing_argument_positional - msg: >- - missing argument for parameter #%0 in call + msg: "missing argument for parameter #%0 in call" - id: missing_arguments_in_call - msg: >- - missing arguments for parameters %0 in call + msg: "missing arguments for parameters %0 in call" - id: extra_argument_named - msg: >- - extra argument %0 in call + msg: "extra argument %0 in call" - id: extra_argument_positional - msg: >- - extra argument in call + msg: "extra argument in call" - id: extra_arguments_in_call - msg: >- - extra arguments at positions %0 in call + msg: "extra arguments at positions %0 in call" - id: extra_argument_to_nullary_call - msg: >- - argument passed to call that takes no arguments + msg: "argument passed to call that takes no arguments" - id: extra_trailing_closure_in_call - msg: >- - extra trailing closure passed in call + msg: "extra trailing closure passed in call" - id: trailing_closure_bad_param - msg: >- - trailing closure passed to parameter of type %0 that does not accept a - closure + msg: "trailing closure passed to parameter of type %0 that does not accept a closure" + +- id: unlabeled_trailing_closure_deprecated + msg: "backward matching of the unlabeled trailing closure is deprecated; label the argument with %0 to suppress this warning" + +- id: decl_multiple_defaulted_closure_parameters + msg: "%0 contains defaulted closure parameters %1 and %2" - id: candidate_with_extraneous_args - msg: >- - candidate %0 requires %1 argument%s1, but %2 %select{were|was}3 - %select{provided|used in closure body}4 + msg: "candidate %0 requires %1 argument%s1, but %2 %select{were|was}3 %select{provided|used in closure body}4" - id: no_accessible_initializers - msg: >- - %0 cannot be constructed because it has no accessible initializers + msg: "%0 cannot be constructed because it has no accessible initializers" - id: non_nominal_no_initializers - msg: >- - non-nominal type %0 does not support explicit initialization + msg: "non-nominal type %0 does not support explicit initialization" - id: unbound_generic_parameter - msg: >- - generic parameter %0 could not be inferred + msg: "generic parameter %0 could not be inferred" - id: unbound_generic_parameter_cast - msg: >- - generic parameter %0 could not be inferred in cast to %1 + msg: "generic parameter %0 could not be inferred in cast to %1" - id: archetype_declared_in_type - msg: >- - %0 declared as parameter to type %1 + msg: "%0 declared as parameter to type %1" - id: unbound_generic_parameter_explicit_fix - msg: >- - explicitly specify the generic arguments to fix this issue + msg: "explicitly specify the generic arguments to fix this issue" - id: invalid_dynamic_callable_type - msg: >- - @dynamicCallable attribute requires %0 to have either a valid - 'dynamicallyCall(withArguments:)' method or - 'dynamicallyCall(withKeywordArguments:)' method + msg: "@dynamicCallable attribute requires %0 to have either a valid 'dynamicallyCall(withArguments:)' method or 'dynamicallyCall(withKeywordArguments:)' method" - id: missing_dynamic_callable_kwargs_method - msg: >- - @dynamicCallable type %0 cannot be applied with keyword arguments; - missing 'dynamicCall(withKeywordArguments:)' method + msg: "@dynamicCallable type %0 cannot be applied with keyword arguments; missing 'dynamicCall(withKeywordArguments:)' method" - id: invalid_dynamic_member_lookup_type - msg: >- - @dynamicMemberLookup attribute requires %0 to have a - 'subscript(dynamicMember:)' method that accepts either - 'ExpressibleByStringLiteral' or a key path + msg: "@dynamicMemberLookup attribute requires %0 to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path" - id: invalid_dynamic_member_subscript - msg: >- - add an explicit argument label to this subscript to satisfy the - @dynamicMemberLookup requirement + msg: "add an explicit argument label to this subscript to satisfy the @dynamicMemberLookup requirement" - id: string_index_not_integer - msg: >- - String must not be indexed with %0, it has variable size elements + msg: "String must not be indexed with %0, it has variable size elements" - id: string_index_not_integer_note - msg: >- - consider using an existing high level algorithm, - str.startIndex.advanced(by: n), or a projection like str.utf8 + msg: "consider using an existing high level algorithm, str.startIndex.advanced(by: n), or a projection like str.utf8" - id: invalid_c_function_pointer_conversion_expr - msg: >- - a C function pointer can only be formed from a reference to a 'func' or a - literal closure + msg: "a C function pointer can only be formed from a reference to a 'func' or a literal closure" - id: c_function_pointer_from_method - msg: >- - a C function pointer cannot be formed from a method + msg: "a C function pointer cannot be formed from a method" - id: c_function_pointer_from_generic_function - msg: >- - a C function pointer cannot be formed from a reference to a generic - function + msg: "a C function pointer cannot be formed from a reference to a generic function" - id: unsupported_linear_to_differentiable_conversion - msg: >- - conversion from '@differentiable(linear)' to '@differentiable' is not yet - supported + msg: "conversion from '@differentiable(linear)' to '@differentiable' is not yet supported" - id: invalid_autoclosure_forwarding - msg: >- - add () to forward @autoclosure parameter + msg: "add () to forward @autoclosure parameter" - id: invalid_differentiable_function_conversion_expr - msg: >- - a '@differentiable%select{|(linear)}0' function can only be formed from a - reference to a 'func' or 'init' or a literal closure + msg: "a '@differentiable%select{|(linear)}0' function can only be formed from a reference to a 'func' or 'init' or a literal closure" - id: invalid_differentiable_function_conversion_parameter - msg: >- - did you mean to take a '%0' closure? + msg: "did you mean to take a '%0' closure?" - id: invalid_autoclosure_pointer_conversion - msg: >- - cannot perform pointer conversion of value of type %0 to autoclosure - result type %1 + msg: "cannot perform pointer conversion of value of type %0 to autoclosure result type %1" - id: missing_initializer_def - msg: >- - initializer requires a body + msg: "initializer requires a body" - id: pound_warning - msg: >- - %0 + msg: "%0" - id: pound_error - msg: >- - %0 + msg: "%0" - id: operator_not_func - msg: >- - operators must be declared with 'func' + msg: "operators must be declared with 'func'" - id: redefining_builtin_operator - msg: >- - cannot declare a custom %0 '%1' operator + msg: "cannot declare a custom %0 '%1' operator" - id: attribute_requires_operator_identifier - msg: >- - '%0' requires a function with an operator identifier + msg: "'%0' requires a function with an operator identifier" - id: attribute_requires_single_argument - msg: >- - '%0' requires a function with one argument + msg: "'%0' requires a function with one argument" - id: nominal_type_not_attribute - msg: >- - %0 %1 cannot be used as an attribute + msg: "%0 %1 cannot be used as an attribute" - id: mutating_invalid_global_scope - msg: >- - %0 is only valid on methods + msg: "%0 is only valid on methods" - id: mutating_invalid_classes - msg: >- - %0 isn't valid on methods in classes or class-bound protocols + msg: "%0 isn't valid on methods in classes or class-bound protocols" - id: functions_mutating_and_not - msg: >- - method must not be declared both %0 and %1 + msg: "method must not be declared both %0 and %1" - id: static_functions_not_mutating - msg: >- - static functions must not be declared mutating + msg: "static functions must not be declared mutating" - id: modify_mutatingness_differs_from_setter - msg: >- - 'modify' accessor cannot be %0 when the setter is %1 + msg: "'modify' accessor cannot be %0 when the setter is %1" - id: transparent_in_protocols_not_supported - msg: >- - '@_transparent' attribute is not supported on declarations within - protocols + msg: "'@_transparent' attribute is not supported on declarations within protocols" - id: transparent_in_classes_not_supported - msg: >- - '@_transparent' attribute is not supported on declarations within classes + msg: "'@_transparent' attribute is not supported on declarations within classes" - id: invalid_iboutlet - msg: >- - only instance properties can be declared @IBOutlet + msg: "only instance properties can be declared @IBOutlet" - id: iboutlet_nonobjc_class - msg: >- - @IBOutlet property cannot %select{have|be an array of}0 non-'@objc' class - type %1 + msg: "@IBOutlet property cannot %select{have|be an array of}0 non-'@objc' class type %1" - id: iboutlet_nonobjc_protocol - msg: >- - @IBOutlet property cannot %select{have|be an array of}0 non-'@objc' - protocol type %1 + msg: "@IBOutlet property cannot %select{have|be an array of}0 non-'@objc' protocol type %1" - id: iboutlet_nonobject_type - msg: >- - @IBOutlet property cannot %select{have|be an array of}0 non-object type %1 + msg: "@IBOutlet property cannot %select{have|be an array of}0 non-object type %1" - id: iboutlet_only_mutable - msg: >- - @IBOutlet attribute requires property to be mutable + msg: "@IBOutlet attribute requires property to be mutable" - id: iboutlet_non_optional - msg: >- - @IBOutlet property has non-optional type %0 + msg: "@IBOutlet property has non-optional type %0" - id: note_make_optional - msg: >- - add '?' to form the optional type %0 + msg: "add '?' to form the optional type %0" - id: note_make_implicitly_unwrapped_optional - msg: >- - add '!' to form an implicitly unwrapped optional + msg: "add '!' to form an implicitly unwrapped optional" - id: invalid_ibdesignable_extension - msg: >- - @IBDesignable can only be applied to classes and extensions of classes + msg: "@IBDesignable can only be applied to classes and extensions of classes" - id: invalid_ibinspectable - msg: >- - only instance properties can be declared @%0 + msg: "only instance properties can be declared @%0" - id: invalid_ibaction_decl - msg: >- - only instance methods can be declared @%0 + msg: "only instance methods can be declared @%0" - id: invalid_ibaction_result - msg: >- - methods declared @%0 must %select{|not }1return a value + msg: "methods declared @%0 must %select{|not }1return a value" - id: invalid_ibaction_argument_count - msg: >- - @%0 methods must have %1 to %2 arguments + msg: "@%0 methods must have %1 to %2 arguments" - id: invalid_ibaction_argument_count_exact - msg: >- - @%0 methods must have %2 argument%s2 + msg: "@%0 methods must have %2 argument%s2" - id: invalid_ibaction_argument_count_max - msg: >- - @%0 methods must have at most %2 argument%s2 + msg: "@%0 methods must have at most %2 argument%s2" - id: ibsegueaction_objc_method_family - msg: >- - @%0 method cannot have selector %1 because it has special memory - management behavior + msg: "@%0 method cannot have selector %1 because it has special memory management behavior" - id: fixit_rename_in_swift - msg: >- - change Swift name to %0 + msg: "change Swift name to %0" - id: fixit_rename_in_objc - msg: >- - change Objective-C selector to %0 + msg: "change Objective-C selector to %0" - id: no_objc_tagged_pointer_not_class_protocol - msg: >- - @unsafe_no_objc_tagged_pointer can only be applied to class protocols + msg: "@unsafe_no_objc_tagged_pointer can only be applied to class protocols" - id: swift_native_objc_runtime_base_not_on_root_class - msg: >- - @_swift_native_objc_runtime_base_not_on_root_class can only be applied to - root classes + msg: "@_swift_native_objc_runtime_base_not_on_root_class can only be applied to root classes" - id: cdecl_not_at_top_level - msg: >- - @_cdecl can only be applied to global functions + msg: "@_cdecl can only be applied to global functions" - id: cdecl_empty_name - msg: >- - @_cdecl symbol name cannot be empty + msg: "@_cdecl symbol name cannot be empty" - id: cdecl_throws - msg: >- - raising errors from @_cdecl functions is not supported + msg: "raising errors from @_cdecl functions is not supported" - id: attr_methods_only - msg: >- - only methods can be declared %0 + msg: "only methods can be declared %0" - id: access_control_in_protocol - msg: >- - %0 modifier cannot be used in protocols + msg: "%0 modifier cannot be used in protocols" - id: access_control_in_protocol_detail - msg: >- - protocol requirements implicitly have the same access as the protocol - itself + msg: "protocol requirements implicitly have the same access as the protocol itself" - id: access_control_setter - msg: >- - '%select{private|fileprivate|internal|public|open}0(set)' modifier can - only be applied to variables and subscripts + msg: "'%select{private|fileprivate|internal|public|open}0(set)' modifier can only be applied to variables and subscripts" - id: access_control_setter_read_only - msg: >- - '%select{private|fileprivate|internal|public|%error}0(set)' modifier - cannot be applied to %select{constants|read-only variables|read-only - properties|read-only subscripts}1 + msg: "'%select{private|fileprivate|internal|public|%error}0(set)' modifier cannot be applied to %select{constants|read-only variables|read-only properties|read-only subscripts}1" - id: access_control_setter_more - msg: >- - %select{private|fileprivate|internal|public|%error}0 - %select{variable|property|subscript}1 cannot have %select{%error|a - fileprivate|an internal|a public|an open}2 setter + msg: "%select{private|fileprivate|internal|public|%error}0 %select{variable|property|subscript}1 cannot have %select{%error|a fileprivate|an internal|a public|an open}2 setter" - id: access_control_setter_redundant - msg: >- - '%select{private|fileprivate|internal|public|open}0(set)' modifier is - redundant for - %select{a private|a fileprivate|an internal|a public|an open}2 %1 + msg: "'%select{private|fileprivate|internal|public|open}0(set)' modifier is redundant for %select{a private|a fileprivate|an internal|a public|an open}2 %1" - id: access_control_ext_member_more - msg: >- - '%select{%error|fileprivate|internal|public|open}0' modifier conflicts - with extension's default access of - '%select{private|fileprivate|internal|public|%error}1' + msg: "'%select{%error|fileprivate|internal|public|open}0' modifier conflicts with extension's default access of '%select{private|fileprivate|internal|public|%error}1'" - id: access_control_ext_member_redundant - msg: >- - '%select{%error|fileprivate|internal|public|%error}0' modifier is - redundant for %1 declared in %select{a private (equivalent to fileprivate)|a - fileprivate|an internal|a public|%error}2 extension + msg: "'%select{%error|fileprivate|internal|public|%error}0' modifier is redundant for %1 declared in %select{a private (equivalent to fileprivate)|a fileprivate|an internal|a public|%error}2 extension" - id: access_control_ext_requirement_member_more - msg: >- - cannot declare %select{%error|a fileprivate|an internal|a public|an - open}0 %1 in an extension with - %select{private|fileprivate|internal|public|%error}2 requirements + msg: "cannot declare %select{%error|a fileprivate|an internal|a public|an open}0 %1 in an extension with %select{private|fileprivate|internal|public|%error}2 requirements" - id: access_control_extension_more - msg: >- - extension of %select{private|fileprivate|internal|%error|%error}0 %1 - cannot be declared %select{%error|fileprivate|internal|public|%error}2 + msg: "extension of %select{private|fileprivate|internal|%error|%error}0 %1 cannot be declared %select{%error|fileprivate|internal|public|%error}2" - id: access_control_extension_open - msg: >- - extensions cannot use 'open' as their default access; use 'public' + msg: "extensions cannot use 'open' as their default access; use 'public'" - id: access_control_open_bad_decl - msg: >- - only classes and overridable class members can be declared 'open'; use - 'public' + msg: "only classes and overridable class members can be declared 'open'; use 'public'" - id: invalid_decl_attribute - msg: >- - '%0' attribute cannot be applied to this declaration + msg: "'%0' attribute cannot be applied to this declaration" - id: invalid_decl_modifier - msg: >- - %0 modifier cannot be applied to this declaration + msg: "%0 modifier cannot be applied to this declaration" - id: attribute_does_not_apply_to_type - msg: >- - attribute does not apply to type + msg: "attribute does not apply to type" - id: optional_attribute_non_protocol - msg: >- - 'optional' can only be applied to protocol members + msg: "'optional' can only be applied to protocol members" - id: optional_attribute_non_objc_protocol - msg: >- - 'optional' can only be applied to members of an @objc protocol + msg: "'optional' can only be applied to members of an @objc protocol" - id: optional_attribute_missing_explicit_objc - msg: >- - 'optional' requirements are an Objective-C compatibility feature; add - '@objc' + msg: "'optional' requirements are an Objective-C compatibility feature; add '@objc'" - id: objcmembers_attribute_nonclass - msg: >- - '@objcMembers' attribute can only be applied to a class + msg: "'@objcMembers' attribute can only be applied to a class" - id: optional_attribute_initializer - msg: >- - 'optional' cannot be applied to an initializer + msg: "'optional' cannot be applied to an initializer" - id: unavailable_method_non_objc_protocol - msg: >- - protocol members can only be marked unavailable in an @objc protocol + msg: "protocol members can only be marked unavailable in an @objc protocol" - id: missing_in_class_init_1 - msg: >- - stored property %0 requires an initial value%select{| or should be - @NSManaged}1 + msg: "stored property %0 requires an initial value%select{| or should be @NSManaged}1" - id: missing_in_class_init_2 - msg: >- - stored properties %0 and %1 require initial values%select{| or should be - @NSManaged}2 + msg: "stored properties %0 and %1 require initial values%select{| or should be @NSManaged}2" - id: missing_in_class_init_3plus - msg: >- - stored properties %0, %1, %select{and %2|%2, and others}3 require initial - values%select{| or should be @NSManaged}4 + msg: "stored properties %0, %1, %select{and %2|%2, and others}3 require initial values%select{| or should be @NSManaged}4" - id: requires_stored_property_inits_here - msg: >- - %select{superclass|class}1 %0 requires all stored properties to have - initial values%select{| or use @NSManaged}2 + msg: "%select{superclass|class}1 %0 requires all stored properties to have initial values%select{| or use @NSManaged}2" - id: class_without_init - msg: >- - class %0 has no initializers + msg: "class %0 has no initializers" - id: note_no_in_class_init_1 - msg: >- - stored property %0 without initial value prevents synthesized - initializers + msg: "stored property %0 without initial value prevents synthesized initializers" - id: note_no_in_class_init_2 - msg: >- - stored properties %0 and %1 without initial values prevent synthesized - initializers + msg: "stored properties %0 and %1 without initial values prevent synthesized initializers" - id: note_no_in_class_init_3plus - msg: >- - stored properties %0, %1, %select{and %2|%2, and others}3 without initial - values prevent synthesized initializers + msg: "stored properties %0, %1, %select{and %2|%2, and others}3 without initial values prevent synthesized initializers" - id: missing_unimplemented_init_runtime - msg: >- - standard library error: missing _unimplementedInitializer + msg: "standard library error: missing _unimplementedInitializer" - id: missing_undefined_runtime - msg: >- - standard library error: missing _undefined + msg: "standard library error: missing _undefined" - id: expr_dynamic_lookup_swift3_objc_inference - msg: >- - reference to %0 %1 of %2 depends on '@objc' inference deprecated in Swift 4 + msg: "reference to %0 %1 of %2 depends on '@objc' inference deprecated in Swift 4" - id: inherited_default_value_not_in_designated_constructor - msg: >- - default value inheritance via 'super' is only valid on the parameters of - designated initializers + msg: "default value inheritance via 'super' is only valid on the parameters of designated initializers" - id: inherited_default_value_used_in_non_overriding_constructor - msg: >- - default value inheritance via 'super' can only be used when overriding a - designated initializer + msg: "default value inheritance via 'super' can only be used when overriding a designated initializer" - id: corresponding_param_not_defaulted - msg: >- - default value inheritance via 'super' requires that the corresponding - parameter of the overridden designated initializer has a default value + msg: "default value inheritance via 'super' requires that the corresponding parameter of the overridden designated initializer has a default value" - id: inherited_default_param_here - msg: >- - corresponding parameter declared here + msg: "corresponding parameter declared here" - id: option_set_zero_constant - msg: >- - static property %0 produces an empty option set + msg: "static property %0 produces an empty option set" - id: option_set_empty_set_init - msg: >- - use [] to silence this warning + msg: "use [] to silence this warning" - id: originally_defined_in_dupe_platform - msg: >- - duplicate version number for platform %0 + msg: "duplicate version number for platform %0" - id: originally_definedin_topleve_decl - msg: >- - @%0 is only applicable to top-level decl + msg: "@%0 is only applicable to top-level decl" - id: originally_definedin_need_available - msg: >- - need @available attribute for @%0 + msg: "need @available attribute for @%0" - id: originally_definedin_must_after_available_version - msg: >- - moved version from @%0 must after introduced OS version + msg: "moved version from @%0 must after introduced OS version" - id: alignment_not_power_of_two - msg: >- - alignment value must be a power of two + msg: "alignment value must be a power of two" - id: indirect_case_without_payload - msg: >- - enum case %0 without associated value cannot be 'indirect' + msg: "enum case %0 without associated value cannot be 'indirect'" - id: indirect_case_in_indirect_enum - msg: >- - enum case in 'indirect' enum cannot also be 'indirect' + msg: "enum case in 'indirect' enum cannot also be 'indirect'" - id: enum_frozen_nonpublic - msg: >- - %0 has no effect on non-public enums + msg: "%0 has no effect on non-public enums" - id: getset_init - msg: >- - variable with getter/setter cannot have an initial value + msg: "variable with getter/setter cannot have an initial value" - id: unimplemented_static_var - msg: >- - %select{ERROR|static|class}1 stored properties not supported%select{ in - this context| in generic types| in classes| - in protocol extensions}0%select{|; did you mean 'static'?}2 + msg: "%select{ERROR|static|class}1 stored properties not supported%select{ in this context| in generic types| in classes| in protocol extensions}0%select{|; did you mean 'static'?}2" - id: observingprop_requires_initializer - msg: >- - non-member observing properties require an initializer + msg: "non-member observing properties require an initializer" - id: global_requires_initializer - msg: >- - global '%select{var|let}0' declaration requires an initializer - expression%select{ or getter/setter specifier|}0 + msg: "global '%select{var|let}0' declaration requires an initializer expression%select{ or getter/setter specifier|}0" - id: static_requires_initializer - msg: >- - %select{ERROR|'static var'|'class var'|}0 declaration requires an - initializer expression or getter/setter specifier + msg: "%select{ERROR|'static var'|'class var'|}0 declaration requires an initializer expression or getter/setter specifier" - id: pattern_type_access - msg: >- - %select{%select{variable|constant}0|property}1 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}3}2 because its type uses %select{a - private|a fileprivate|an internal|%error|%error}5 type + msg: "%select{%select{variable|constant}0|property}1 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - id: pattern_type_access_warn - msg: >- - %select{%select{variable|constant}0|property}1 %select{should be declared - %select{private|fileprivate|internal|%error|%error}5|should not be declared - %select{in this context|fileprivate|internal|public|open}3}2 because its - type uses %select{a private|a fileprivate|an internal|%error|%error}5 type + msg: "%select{%select{variable|constant}0|property}1 %select{should be declared %select{private|fileprivate|internal|%error|%error}5|should not be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - id: pattern_type_access_inferred - msg: >- - %select{%select{variable|constant}0|property}1 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}3}2 because its type %6 - uses %select{a private|a fileprivate|an internal|%error|%error}5 type + msg: "%select{%select{variable|constant}0|property}1 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type %6 uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - id: pattern_type_access_inferred_warn - msg: >- - %select{%select{variable|constant}0|property}1 %select{should be declared - %select{private|fileprivate|internal|%error|%error}5|should not be declared - %select{in this context|fileprivate|internal|public|open}3}2 because its - type %6 uses - %select{a private|a fileprivate|an internal|%error|%error}5 type + msg: "%select{%select{variable|constant}0|property}1 %select{should be declared %select{private|fileprivate|internal|%error|%error}5|should not be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type %6 uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - id: pattern_type_not_usable_from_inline - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 must be '@usableFromInline' - or public + msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 must be '@usableFromInline' or public" - id: pattern_type_not_usable_from_inline_warn - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 should be '@usableFromInline' - or public + msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 should be '@usableFromInline' or public" - id: pattern_type_not_usable_from_inline_frozen - msg: >- - type referenced from a stored property in a '@frozen' struct must be - '@usableFromInline' or public + msg: "type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public" - id: pattern_type_not_usable_from_inline_inferred - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 with inferred type %2 must be - '@usableFromInline' or public + msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 with inferred type %2 must be '@usableFromInline' or public" - id: pattern_type_not_usable_from_inline_inferred_warn - msg: >- - type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 with inferred type %2 should - be '@usableFromInline' or public + msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 with inferred type %2 should be '@usableFromInline' or public" - id: pattern_type_not_usable_from_inline_inferred_frozen - msg: >- - type referenced from a stored property with inferred type %2 in a - '@frozen' struct must be '@usableFromInline' or public + msg: "type referenced from a stored property with inferred type %2 in a '@frozen' struct must be '@usableFromInline' or public" - id: pattern_binds_no_variables - msg: >- - %select{property|global variable}0 declaration does not bind any - variables + msg: "%select{property|global variable}0 declaration does not bind any variables" - id: variable_bound_by_no_pattern - msg: >- - variable %0 is not bound by any pattern + msg: "variable %0 is not bound by any pattern" - id: optional_ambiguous_case_ref - msg: >- - assuming you mean '%0.%2'; did you mean '%1.%2' instead? + msg: "assuming you mean '%0.%2'; did you mean '%1.%2' instead?" - id: optional_fixit_ambiguous_case_ref - msg: >- - explicitly specify 'Optional' to silence this warning + msg: "explicitly specify 'Optional' to silence this warning" - id: optional_fixit_ambiguous_case_ref_switch - msg: >- - use 'nil' to silence this warning + msg: "use 'nil' to silence this warning" - id: type_fixit_optional_ambiguous_case_ref - msg: >- - use '%0.%1' instead + msg: "use '%0.%1' instead" - id: type_fixit_optional_ambiguous_case_ref_switch - msg: >- - use '%0' instead + msg: "use '%0' instead" - id: nscoding_unstable_mangled_name - msg: >- - %select{private|fileprivate|nested|local}0 class %1 has an unstable name - when archiving via 'NSCoding' + msg: "%select{private|fileprivate|nested|local}0 class %1 has an unstable name when archiving via 'NSCoding'" - id: unstable_mangled_name_add_objc_new - msg: >- - for new classes, use '@objc' to specify a unique, prefixed Objective-C - runtime name + msg: "for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name" - id: unstable_mangled_name_add_objc - msg: >- - for compatibility with existing archives, use '@objc' to record the Swift - 3 runtime name + msg: "for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name" - id: unsupported_type_nested_in_generic_function - msg: >- - type %0 cannot be nested in generic function %1 + msg: "type %0 cannot be nested in generic function %1" - id: unsupported_type_nested_in_generic_closure - msg: >- - type %0 cannot be nested in closure in generic context + msg: "type %0 cannot be nested in closure in generic context" - id: unsupported_type_nested_in_protocol - msg: >- - type %0 cannot be nested in protocol %1 + msg: "type %0 cannot be nested in protocol %1" - id: unsupported_type_nested_in_protocol_extension - msg: >- - type %0 cannot be nested in protocol extension of %1 + msg: "type %0 cannot be nested in protocol extension of %1" - id: unsupported_nested_protocol - msg: >- - protocol %0 cannot be nested inside another declaration + msg: "protocol %0 cannot be nested inside another declaration" - id: where_nongeneric_ctx - msg: >- - 'where' clause on non-generic member declaration requires a generic - context + msg: "'where' clause on non-generic member declaration requires a generic context" - id: where_nongeneric_toplevel - msg: >- - 'where' clause cannot be applied to a non-generic top-level declaration + msg: "'where' clause cannot be applied to a non-generic top-level declaration" - id: type_alias_underlying_type_access - msg: >- - type alias %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}3|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its underlying type - uses %select{a private|a fileprivate|an internal|%error|%error}2 type + msg: "type alias %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}3|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its underlying type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - id: type_alias_underlying_type_access_warn - msg: >- - type alias %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - underlying type uses - %select{a private|a fileprivate|an internal|%error|%error}2 type + msg: "type alias %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its underlying type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - id: type_alias_underlying_type_not_usable_from_inline - msg: >- - type referenced from the underlying type of a '@usableFromInline' type - alias must be '@usableFromInline' or public + msg: "type referenced from the underlying type of a '@usableFromInline' type alias must be '@usableFromInline' or public" - id: type_alias_underlying_type_not_usable_from_inline_warn - msg: >- - type referenced from the underlying type of a '@usableFromInline' type - alias should be '@usableFromInline' or public + msg: "type referenced from the underlying type of a '@usableFromInline' type alias should be '@usableFromInline' or public" - id: subscript_type_access - msg: >- - subscript %select{must be declared - %select{private|fileprivate|internal|%error|%error}1|cannot be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - %select{index|element type}3 uses %select{a private|a fileprivate|an - internal|%error|%error}2 type + msg: "subscript %select{must be declared %select{private|fileprivate|internal|%error|%error}1|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{index|element type}3 uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - id: subscript_type_access_warn - msg: >- - subscript %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - %select{index|element type}3 uses %select{a private|a fileprivate|an - internal|%error|%error}2 type + msg: "subscript %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{index|element type}3 uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - id: subscript_type_usable_from_inline - msg: >- - %select{index type|element type}0 of a '@usableFromInline' subscript must - be '@usableFromInline' or public + msg: "%select{index type|element type}0 of a '@usableFromInline' subscript must be '@usableFromInline' or public" - id: subscript_type_usable_from_inline_warn - msg: >- - %select{index type|element type}0 of a '@usableFromInline' subscript - should be '@usableFromInline' or public + msg: "%select{index type|element type}0 of a '@usableFromInline' subscript should be '@usableFromInline' or public" - id: function_type_access - msg: >- - %select{function|method|initializer}4 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}2|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its - %select{parameter|result}5 uses %select{a private|a fileprivate|an internal|an - '@_spi'|an '@_spi'}3 type + msg: "%select{function|method|initializer}4 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}2|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{parameter|result}5 uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type" - id: function_type_spi - msg: >- - %select{function|method|initializer}0 cannot be declared '@_spi' because - its %select{parameter|result}1 uses %select{a private|a fileprivate|an - internal|a public|an open}2 type%select{| that is not '@_spi'}3 + msg: "%select{function|method|initializer}0 cannot be declared '@_spi' because its %select{parameter|result}1 uses %select{a private|a fileprivate|an internal|a public|an open}2 type%select{| that is not '@_spi'}3" - id: function_type_access_warn - msg: >- - %select{function|method|initializer}4 %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - %select{parameter|result}5 uses %select{a private|a fileprivate|an - internal|%error|%error}3 type + msg: "%select{function|method|initializer}4 %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{parameter|result}5 uses %select{a private|a fileprivate|an internal|%error|%error}3 type" - id: function_type_usable_from_inline - msg: >- - the %select{parameter|result}1 of a '@usableFromInline' - %select{function|method|initializer}0 must be '@usableFromInline' or public + msg: "the %select{parameter|result}1 of a '@usableFromInline' %select{function|method|initializer}0 must be '@usableFromInline' or public" - id: function_type_usable_from_inline_warn - msg: >- - the %select{parameter|result}1 of a '@usableFromInline' - %select{function|method|initializer}0 should be '@usableFromInline' - or public + msg: "the %select{parameter|result}1 of a '@usableFromInline' %select{function|method|initializer}0 should be '@usableFromInline' or public" - id: spi_attribute_on_non_public - msg: >- - %select{private|fileprivate|internal|%error|%error}0 %1 cannot be - declared '@_spi' because only public and open declarations can be '@_spi' + msg: "%select{private|fileprivate|internal|%error|%error}0 %1 cannot be declared '@_spi' because only public and open declarations can be '@_spi'" - id: spi_attribute_on_protocol_requirement - msg: >- - protocol requirement %0 cannot be declared '@_spi' without a default - implementation in a protocol extension + msg: "protocol requirement %0 cannot be declared '@_spi' without a default implementation in a protocol extension" - id: spi_attribute_on_frozen_stored_properties - msg: >- - stored property %0 cannot be declared '@_spi' in a '@frozen' struct + msg: "stored property %0 cannot be declared '@_spi' in a '@frozen' struct" - id: opaque_type_invalid_constraint - msg: >- - an 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or - a base class + msg: "an 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or a base class" - id: inferred_opaque_type - msg: >- - property definition has inferred type %0, involving the 'some' return - type of another declaration + msg: "property definition has inferred type %0, involving the 'some' return type of another declaration" - id: non_nominal_extension - msg: >- - non-nominal type %0 cannot be extended + msg: "non-nominal type %0 cannot be extended" - id: composition_in_extended_type - msg: >- - extending a protocol composition is not supported; extending %0 instead + msg: "extending a protocol composition is not supported; extending %0 instead" - id: composition_in_extended_type_alternative - msg: >- - did you mean to extend the most specific type %0 instead? + msg: "did you mean to extend the most specific type %0 instead?" - id: extension_access_with_conformances - msg: >- - %0 modifier cannot be used with extensions that declare protocol - conformances + msg: "%0 modifier cannot be used with extensions that declare protocol conformances" - id: extension_metatype - msg: >- - cannot extend a metatype %0 + msg: "cannot extend a metatype %0" - id: extension_specialization - msg: >- - constrained extension must be declared on the unspecialized generic type - %0 with constraints specified by a 'where' clause + msg: "constrained extension must be declared on the unspecialized generic type %0 with constraints specified by a 'where' clause" - id: extension_stored_property - msg: >- - extensions must not contain stored properties + msg: "extensions must not contain stored properties" - id: extension_stored_property_fixit - msg: >- - Remove '=' to make %0 a computed property + msg: "Remove '=' to make %0 a computed property" - id: extension_nongeneric_trailing_where - msg: >- - trailing 'where' clause for extension of non-generic type %0 + msg: "trailing 'where' clause for extension of non-generic type %0" - id: extension_protocol_inheritance - msg: >- - extension of protocol %0 cannot have an inheritance clause + msg: "extension of protocol %0 cannot have an inheritance clause" - id: objc_generic_extension_using_type_parameter - msg: >- - extension of a generic Objective-C class cannot access the class's - generic parameters at runtime + msg: "extension of a generic Objective-C class cannot access the class's generic parameters at runtime" - id: objc_generic_extension_using_type_parameter_here - msg: >- - generic parameter used here + msg: "generic parameter used here" - id: objc_generic_extension_using_type_parameter_try_objc - msg: >- - add '@objc' to allow uses of 'self' within the function body + msg: "add '@objc' to allow uses of 'self' within the function body" - id: invalid_nominal_extension - msg: >- - extension of type %0 must be declared as an extension of %1 + msg: "extension of type %0 must be declared as an extension of %1" - id: invalid_nominal_extension_rewrite - msg: >- - did you mean to extend %0 instead? + msg: "did you mean to extend %0 instead?" - id: type_does_not_conform - msg: >- - type %0 does not conform to protocol %1 + msg: "type %0 does not conform to protocol %1" - id: cannot_use_nil_with_this_type - msg: >- - 'nil' cannot be used in context expecting type %0 + msg: "'nil' cannot be used in context expecting type %0" - id: type_cannot_conform_to_nsobject - msg: >- - cannot declare conformance to 'NSObjectProtocol' in Swift; %0 should - inherit 'NSObject' instead + msg: "cannot declare conformance to 'NSObjectProtocol' in Swift; %0 should inherit 'NSObject' instead" - id: use_of_equal_instead_of_equality - msg: >- - use of '=' in a boolean context, did you mean '=='? + msg: "use of '=' in a boolean context, did you mean '=='?" - id: type_cannot_conform - msg: >- - %select{type %1|protocol %1 as a type}0 cannot conform to - %select{%3|the protocol itself}2; - only concrete types such as structs, enums and classes - can conform to protocols + msg: "%select{type %1|protocol %1 as a type}0 cannot conform to %select{%3|the protocol itself}2; only concrete types such as structs, enums and classes can conform to protocols" - id: required_by_opaque_return - msg: >- - required by opaque return type of %0 %1 + msg: "required by opaque return type of %0 %1" - id: required_by_decl - msg: >- - required by %0 %1 where %2 = %3 + msg: "required by %0 %1 where %2 = %3" - id: required_by_decl_ref - msg: >- - required by referencing %0 %1 on %2 where %3 = %4 + msg: "required by referencing %0 %1 on %2 where %3 = %4" - id: protocol_does_not_conform_static - msg: >- - %0 cannot be used as a type conforming to protocol %1 because %1 has - static requirements + msg: "%0 cannot be used as a type conforming to protocol %1 because %1 has static requirements" - id: protocol_derivation_is_broken - msg: >- - protocol %0 is broken; cannot derive conformance for type %1 + msg: "protocol %0 is broken; cannot derive conformance for type %1" - id: type_does_not_inherit - msg: >- - %0 requires that %1 inherit from %2 + msg: "%0 requires that %1 inherit from %2" - id: type_does_not_inherit_or_conform_requirement - msg: >- - requirement specified as %0 : %1%2 + msg: "requirement specified as %0 : %1%2" - id: types_not_equal - msg: >- - %0 requires the types %1 and %2 be equivalent + msg: "%0 requires the types %1 and %2 be equivalent" - id: type_does_not_conform_owner - msg: >- - %0 requires that %1 conform to %2 + msg: "%0 requires that %1 conform to %2" - id: type_does_not_conform_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires that %3 conform to %4 + msg: "referencing %0 %1 on %2 requires that %3 conform to %4" - id: type_does_not_conform_anyobject_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires that %3 be a class type + msg: "referencing %0 %1 on %2 requires that %3 be a class type" - id: type_does_not_conform_decl_owner - msg: >- - %0 %1 requires that %2 conform to %3 + msg: "%0 %1 requires that %2 conform to %3" - id: type_does_not_conform_anyobject_decl_owner - msg: >- - %0 %1 requires that %2 be a class type + msg: "%0 %1 requires that %2 be a class type" - id: type_does_not_conform_in_opaque_return - msg: >- - return type of %0 %1 requires that %2 - %select{conform to %3|be a class type}4 + msg: "return type of %0 %1 requires that %2 %select{conform to %3|be a class type}4" - id: types_not_equal_decl - msg: >- - %0 %1 requires the types %2 and %3 be equivalent + msg: "%0 %1 requires the types %2 and %3 be equivalent" - id: types_not_equal_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires the types %3 and %4 be equivalent + msg: "referencing %0 %1 on %2 requires the types %3 and %4 be equivalent" - id: types_not_inherited_decl - msg: >- - %0 %1 requires that %2 inherit from %3 + msg: "%0 %1 requires that %2 inherit from %3" - id: types_not_inherited_in_decl_ref - msg: >- - referencing %0 %1 on %2 requires that %3 inherit from %4 + msg: "referencing %0 %1 on %2 requires that %3 inherit from %4" - id: where_requirement_failure_one_subst - msg: >- - where %0 = %1 + msg: "where %0 = %1" - id: where_requirement_failure_both_subst - msg: >- - where %0 = %1, %2 = %3 + msg: "where %0 = %1, %2 = %3" - id: requirement_implied_by_conditional_conformance - msg: >- - requirement from conditional conformance of %0 to %1 + msg: "requirement from conditional conformance of %0 to %1" - id: wrapped_type_satisfies_requirement - msg: >- - wrapped type %0 satisfies this requirement; did you mean to unwrap? + msg: "wrapped type %0 satisfies this requirement; did you mean to unwrap?" - id: candidate_types_conformance_requirement - msg: >- - candidate requires that %0 conform to %1 - (requirement specified as %2 == %3%4) + msg: "candidate requires that %0 conform to %1 (requirement specified as %2 == %3%4)" - id: candidate_types_equal_requirement - msg: >- - candidate requires that the types %0 and %1 be equivalent (requirement - specified as %2 == %3%4) + msg: "candidate requires that the types %0 and %1 be equivalent (requirement specified as %2 == %3%4)" - id: candidate_types_inheritance_requirement - msg: >- - candidate requires that %1 inherit from %2 - (requirement specified as %2 : %3%4) + msg: "candidate requires that %1 inherit from %2 (requirement specified as %2 : %3%4)" - id: types_not_equal_requirement - msg: >- - requirement specified as %0 == %1%2 + msg: "requirement specified as %0 == %1%2" - id: type_is_not_a_class - msg: >- - %0 requires that %1 be a class type + msg: "%0 requires that %1 be a class type" - id: anyobject_requirement - msg: >- - requirement specified as %0 : 'AnyObject'%2 + msg: "requirement specified as %0 : 'AnyObject'%2" - id: non_class_cannot_conform_to_class_protocol - msg: >- - non-class type %0 cannot conform to class protocol %1 + msg: "non-class type %0 cannot conform to class protocol %1" - id: cf_class_cannot_conform_to_objc_protocol - msg: >- - Core Foundation class %0 cannot conform to @objc protocol %1 because Core - Foundation types are not classes in Objective-C + msg: "Core Foundation class %0 cannot conform to @objc protocol %1 because Core Foundation types are not classes in Objective-C" - id: objc_runtime_visible_cannot_conform_to_objc_protocol - msg: >- - class %0 cannot conform to @objc protocol %1 because the class is only - visible via the Objective-C runtime + msg: "class %0 cannot conform to @objc protocol %1 because the class is only visible via the Objective-C runtime" - id: objc_generics_cannot_conditionally_conform - msg: >- - type %0 cannot conditionally conform to protocol %1 because the type uses - the Objective-C generics model + msg: "type %0 cannot conditionally conform to protocol %1 because the type uses the Objective-C generics model" - id: objc_protocol_cannot_have_conditional_conformance - msg: >- - type %0 cannot conditionally conform to @objc protocol %1 because - Objective-C does not support conditional conformances + msg: "type %0 cannot conditionally conform to @objc protocol %1 because Objective-C does not support conditional conformances" - id: objc_protocol_in_generic_extension - msg: >- - conformance of %select{class from generic context|generic class}0 %1 to - @objc protocol %2 cannot be in an extension + msg: "conformance of %select{class from generic context|generic class}0 %1 to @objc protocol %2 cannot be in an extension" - id: conditional_conformances_cannot_imply_conformances - msg: >- - conditional conformance of type %0 to protocol %1 does not imply - conformance to inherited protocol %2 + msg: "conditional conformance of type %0 to protocol %1 does not imply conformance to inherited protocol %2" - id: note_explicitly_state_conditional_conformance_different - msg: >- - did you mean to explicitly state the conformance with different bounds? + msg: "did you mean to explicitly state the conformance with different bounds?" - id: note_explicitly_state_conditional_conformance_relaxed - msg: >- - did you mean to explicitly state the conformance with relaxed bounds? + msg: "did you mean to explicitly state the conformance with relaxed bounds?" - id: note_explicitly_state_conditional_conformance_same - msg: >- - did you mean to explicitly state the conformance with the same bounds? + msg: "did you mean to explicitly state the conformance with the same bounds?" - id: note_explicitly_state_conditional_conformance_noneditor - msg: >- - did you mean to explicitly state the conformance like '%0where ...'? + msg: "did you mean to explicitly state the conformance like '%0where ...'?" - id: protocol_has_missing_requirements - msg: >- - type %0 cannot conform to protocol %1 because it has requirements that - cannot be satisfied + msg: "type %0 cannot conform to protocol %1 because it has requirements that cannot be satisfied" - id: protocol_has_missing_requirements_versioned - msg: >- - type %0 cannot conform to protocol %1 (compiled with Swift %2) because it - has requirements that could not be loaded in Swift %3 + msg: "type %0 cannot conform to protocol %1 (compiled with Swift %2) because it has requirements that could not be loaded in Swift %3" - id: requirement_restricts_self - msg: >- - %0 requirement %1 cannot add constraint '%2%select{:|:| ==|:}3 %4' on 'Self' + msg: "%0 requirement %1 cannot add constraint '%2%select{:|:| ==|:}3 %4' on 'Self'" - id: witness_argument_name_mismatch - msg: >- - %0 %1 has different argument labels from those required by protocol %2 (%3) + msg: "%0 %1 has different argument labels from those required by protocol %2 (%3)" - id: witness_initializer_not_required - msg: >- - initializer requirement %0 can only be satisfied by a 'required' - initializer in%select{| the definition of}1 non-final class %2 + msg: "initializer requirement %0 can only be satisfied by a 'required' initializer in%select{| the definition of}1 non-final class %2" - id: witness_initializer_failability - msg: >- - non-failable initializer requirement %0%select{| in Objective-C - protocol}1 cannot be satisfied by a - failable initializer ('init%select{?|!}1') + msg: "non-failable initializer requirement %0%select{| in Objective-C protocol}1 cannot be satisfied by a failable initializer ('init%select{?|!}1')" - id: witness_self_non_subtype - msg: >- - protocol %0 requirement %1 cannot be satisfied by a non-final class (%2) - because it uses 'Self' in a non-parameter, non-result type position + msg: "protocol %0 requirement %1 cannot be satisfied by a non-final class (%2) because it uses 'Self' in a non-parameter, non-result type position" - id: witness_self_same_type - msg: >- - %0 %1 in non-final class %2 cannot be used to satisfy requirement %3 %4 - (in protocol %5) due to same-type requirement involving 'Self' + msg: "%0 %1 in non-final class %2 cannot be used to satisfy requirement %3 %4 (in protocol %5) due to same-type requirement involving 'Self'" - id: witness_self_weaken_same_type - msg: >- - consider weakening the same-type requirement %0 == %1 to a superclass - requirement + msg: "consider weakening the same-type requirement %0 == %1 to a superclass requirement" - id: witness_requires_dynamic_self - msg: >- - method %0 in non-final class %1 must return 'Self' to conform to protocol %2 + msg: "method %0 in non-final class %1 must return 'Self' to conform to protocol %2" - id: witness_requires_class_implementation - msg: >- - method %0 in non-final class %1 cannot be implemented in a protocol - extension because it returns 'Self' and has associated type requirements + msg: "method %0 in non-final class %1 cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements" - id: witness_not_accessible_proto - msg: >- - %select{initializer %1|method %1|%select{|setter for }2property - %1|subscript%select{| setter}2}0 must be declared - %select{%error|fileprivate|internal|public|%error}3 because it matches a - requirement in %select{private|fileprivate|internal|public|%error}4 - protocol %5 + msg: "%select{initializer %1|method %1|%select{|setter for }2property %1|subscript%select{| setter}2}0 must be declared %select{%error|fileprivate|internal|public|%error}3 because it matches a requirement in %select{private|fileprivate|internal|public|%error}4 protocol %5" - id: witness_not_accessible_type - msg: >- - %select{initializer %1|method %1|%select{|setter for }2property - %1|subscript%select{| setter}2}0 must be as accessible as its enclosing type - because it matches a requirement in protocol %5 + msg: "%select{initializer %1|method %1|%select{|setter for }2property %1|subscript%select{| setter}2}0 must be as accessible as its enclosing type because it matches a requirement in protocol %5" - id: type_witness_not_accessible_proto - msg: >- - %0 %1 must be declared - %select{%error|fileprivate|internal|public|%error}2 because it matches a - requirement in %select{%error|fileprivate|internal|public|%error}2 - protocol %3 + msg: "%0 %1 must be declared %select{%error|fileprivate|internal|public|%error}2 because it matches a requirement in %select{%error|fileprivate|internal|public|%error}2 protocol %3" - id: type_witness_not_accessible_type - msg: >- - %0 %1 must be as accessible as its enclosing type because it matches a - requirement in protocol %3 + msg: "%0 %1 must be as accessible as its enclosing type because it matches a requirement in protocol %3" - id: witness_not_usable_from_inline - msg: >- - %0 %1 must be declared '@usableFromInline' because it matches a - requirement in protocol %2 + msg: "%0 %1 must be declared '@usableFromInline' because it matches a requirement in protocol %2" - id: witness_not_usable_from_inline_warn - msg: >- - %0 %1 should be declared '@usableFromInline' because it matches a - requirement in protocol %2 + msg: "%0 %1 should be declared '@usableFromInline' because it matches a requirement in protocol %2" - id: type_witness_objc_generic_parameter - msg: >- - type %0 involving Objective-C type parameter%select{| %1}2 cannot be used - for associated type %3 of protocol %4 + msg: "type %0 involving Objective-C type parameter%select{| %1}2 cannot be used for associated type %3 of protocol %4" - id: witness_fix_access - msg: >- - mark the %0 as '%select{%error|fileprivate|internal|public|%error}1' to - satisfy the requirement + msg: "mark the %0 as '%select{%error|fileprivate|internal|public|%error}1' to satisfy the requirement" - id: witness_move_to_another_extension - msg: >- - move the %0 to another extension where it can be declared - '%select{%error|%error|internal|public|%error}1' to satisfy the requirement + msg: "move the %0 to another extension where it can be declared '%select{%error|%error|internal|public|%error}1' to satisfy the requirement" - id: assoc_type_default_conformance_failed - msg: >- - default type %0 for associated type %1 does not satisfy constraint %2: %3 + msg: "default type %0 for associated type %1 does not satisfy constraint %2: %3" - id: assoc_type_default_here - msg: >- - associated type %0 has default type %1 written here + msg: "associated type %0 has default type %1 written here" - id: protocol_access - msg: >- - %select{protocol must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}4 because - %select{it refines|its 'where' clause uses}2|%select{in - this context|fileprivate|internal|public|%error}1 %select{protocol cannot - refine|protocol's 'where' clause cannot use}2}0 %select{a private|a - fileprivate|an internal|%error|%error}3 %5 + msg: "%select{protocol must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}4 because %select{it refines|its 'where' clause uses}2|%select{in this context|fileprivate|internal|public|%error}1 %select{protocol cannot refine|protocol's 'where' clause cannot use}2}0 %select{a private|a fileprivate|an internal|%error|%error}3 %5" - id: protocol_access_warn - msg: >- - %select{protocol should be declared - %select{private|fileprivate|internal|%error|%error}1 because %select{it - refines|its 'where' clause uses}2|%select{in this - context|fileprivate|internal|public|%error}1 %select{protocol should not - refine|protocol's 'where' clause should not use}2}0 %select{a private|a - fileprivate|an internal|%error|%error}3 %5 + msg: "%select{protocol should be declared %select{private|fileprivate|internal|%error|%error}1 because %select{it refines|its 'where' clause uses}2|%select{in this context|fileprivate|internal|public|%error}1 %select{protocol should not refine|protocol's 'where' clause should not use}2}0 %select{a private|a fileprivate|an internal|%error|%error}3 %5" - id: protocol_usable_from_inline - msg: >- - protocol %select{refined|used}0 by '@usableFromInline' protocol must be - '@usableForInline' or public + msg: "protocol %select{refined|used}0 by '@usableFromInline' protocol must be '@usableForInline' or public" - id: protocol_usable_from_inline_warn - msg: >- - protocol %select{refined|used}0 by '@usableFromInline' protocol should be - '@usableForInline' or public + msg: "protocol %select{refined|used}0 by '@usableFromInline' protocol should be '@usableForInline' or public" - id: protocol_property_must_be_computed_var - msg: >- - protocols cannot require properties to be immutable; declare read-only - properties by using 'var' with a '{ get }' specifier + msg: "protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier" - id: protocol_property_must_be_computed - msg: >- - property in protocol must have explicit { get } or { get set } specifier + msg: "property in protocol must have explicit { get } or { get set } specifier" - id: inherited_protocol_does_not_conform - msg: >- - type %0 does not conform to inherited protocol %1 + msg: "type %0 does not conform to inherited protocol %1" - id: no_witnesses - msg: >- - protocol requires %select{initializer %1|function %1|property - %1|subscript}0 with type %2%select{|; do you want to add a stub?}3 + msg: "protocol requires %select{initializer %1|function %1|property %1|subscript}0 with type %2%select{|; do you want to add a stub?}3" - id: missing_witnesses_general - msg: >- - do you want to add protocol stubs? + msg: "do you want to add protocol stubs?" - id: ambiguous_witnesses - msg: >- - multiple matching %select{initializers named %1|functions named - %1|properties named %1|subscript operators}0 with type %2 + msg: "multiple matching %select{initializers named %1|functions named %1|properties named %1|subscript operators}0 with type %2" - id: ambiguous_witnesses_wrong_name - msg: >- - multiple matching %select{initializers named %1|functions named - %1|properties named %1|subscript operators}0 with type %2 + msg: "multiple matching %select{initializers named %1|functions named %1|properties named %1|subscript operators}0 with type %2" - id: no_witnesses_type - msg: >- - protocol requires nested type %0; do you want to add it? + msg: "protocol requires nested type %0; do you want to add it?" - id: default_associated_type_req_fail - msg: >- - default type %0 for associated type %1 (from protocol %2) does not - %select{inherit from|conform to}4 %3 + msg: "default type %0 for associated type %1 (from protocol %2) does not %select{inherit from|conform to}4 %3" - id: associated_type_access - msg: >- - associated type in %select{a private|a fileprivate|an internal|a - public|%error}0 protocol uses %select{a private|a fileprivate|an - internal|%error|%error}1 type in its - %select{default definition|requirement}2 + msg: "associated type in %select{a private|a fileprivate|an internal|a public|%error}0 protocol uses %select{a private|a fileprivate|an internal|%error|%error}1 type in its %select{default definition|requirement}2 " - id: associated_type_access_warn - msg: >- - associated type in %select{a private|a fileprivate|an internal|a - public|%error}0 protocol uses %select{a private|a fileprivate|an - internal|%error|%error}1 type in its - %select{default definition|requirement}2 + msg: "associated type in %select{a private|a fileprivate|an internal|a public|%error}0 protocol uses %select{a private|a fileprivate|an internal|%error|%error}1 type in its %select{default definition|requirement}2 " - id: associated_type_not_usable_from_inline - msg: >- - type referenced from a %select{default definition|requirement}0 of an - associated type in a '@usableFromInline' - protocol must be '@usableFromInline' or public + msg: "type referenced from a %select{default definition|requirement}0 of an associated type in a '@usableFromInline' protocol must be '@usableFromInline' or public" - id: associated_type_not_usable_from_inline_warn - msg: >- - type referenced from a %select{default definition|requirement}0 of an - associated type in a '@usableFromInline' - protocol should be '@usableFromInline' or public + msg: "type referenced from a %select{default definition|requirement}0 of an associated type in a '@usableFromInline' protocol should be '@usableFromInline' or public" - id: bad_associated_type_deduction - msg: >- - unable to infer associated type %0 for protocol %1 + msg: "unable to infer associated type %0 for protocol %1" - id: associated_type_deduction_witness_failed - msg: >- - candidate would match and infer %0 = %1 if %1 %select{inherited - from|conformed to}3 %2 + msg: "candidate would match and infer %0 = %1 if %1 %select{inherited from|conformed to}3 %2" - id: associated_type_witness_conform_impossible - msg: >- - candidate can not infer %0 = %1 because %1 is not a nominal type and so - can't conform to %2 + msg: "candidate can not infer %0 = %1 because %1 is not a nominal type and so can't conform to %2" - id: associated_type_witness_inherit_impossible - msg: >- - candidate can not infer %0 = %1 because %1 is not a class type and so - can't inherit from %2 + msg: "candidate can not infer %0 = %1 because %1 is not a class type and so can't inherit from %2" - id: ambiguous_associated_type_deduction - msg: >- - ambiguous inference of associated type %0: %1 vs. %2 + msg: "ambiguous inference of associated type %0: %1 vs. %2" - id: associated_type_deduction_witness - msg: >- - matching requirement %0 to this declaration inferred associated type to %1 + msg: "matching requirement %0 to this declaration inferred associated type to %1" - id: associated_type_deduction_default - msg: >- - using associated type default %0 + msg: "using associated type default %0" - id: ambiguous_witnesses_type - msg: >- - multiple matching types named %0 + msg: "multiple matching types named %0" - id: protocol_witness_exact_match - msg: >- - candidate exactly matches%0 + msg: "candidate exactly matches%0" - id: protocol_witness_renamed - msg: >- - rename to %0 to satisfy this requirement%1 + msg: "rename to %0 to satisfy this requirement%1" - id: protocol_witness_kind_conflict - msg: >- - candidate is not %select{an initializer|a function|a variable|a subscript}0 + msg: "candidate is not %select{an initializer|a function|a variable|a subscript}0" - id: protocol_witness_type_conflict - msg: >- - candidate has non-matching type %0%1 + msg: "candidate has non-matching type %0%1" - id: protocol_witness_missing_requirement - msg: >- - candidate would match if %0 %select{conformed to|subclassed|was the same - type as}2 %1 + msg: "candidate would match if %0 %select{conformed to|subclassed|was the same type as}2 %1" - id: protocol_witness_optionality_conflict - msg: >- - candidate %select{type has|result type has|parameter type has|parameter - types have|result and parameter types have}0 incorrect optionality%1 + msg: "candidate %select{type has|result type has|parameter type has|parameter types have|result and parameter types have}0 incorrect optionality%1" - id: err_protocol_witness_optionality - msg: >- - %select{type|result|parameter|parameters|result and parameters}0 of %1 - %select{has|has|has|have|have|}0 - different optionality than required by protocol %2 + msg: "%select{type|result|parameter|parameters|result and parameters}0 of %1 %select{has|has|has|have|have|}0 different optionality than required by protocol %2" - id: warn_protocol_witness_optionality - msg: >- - %select{type|result|parameter|parameters|result and parameters}0 of %1 - %select{has|has|has|have|have|}0 different optionality than expected by - protocol %2 + msg: "%select{type|result|parameter|parameters|result and parameters}0 of %1 %select{has|has|has|have|have|}0 different optionality than expected by protocol %2" - id: protocol_witness_static_conflict - msg: >- - candidate operates on %select{a type|an instance}0, not %select{an - instance|a type}0 as required + msg: "candidate operates on %select{a type|an instance}0, not %select{an instance|a type}0 as required" - id: protocol_witness_prefix_postfix_conflict - msg: >- - candidate is %select{|prefix, |postfix, }1not %select{prefix|postfix}0 as - required + msg: "candidate is %select{|prefix, |postfix, }1not %select{prefix|postfix}0 as required" - id: protocol_witness_mutation_modifier_conflict - msg: >- - candidate is marked %0 but protocol does not allow it + msg: "candidate is marked %0 but protocol does not allow it" - id: protocol_witness_settable_conflict - msg: >- - candidate is not settable, but protocol requires it + msg: "candidate is not settable, but protocol requires it" - id: protocol_witness_rethrows_conflict - msg: >- - candidate is not 'rethrows', but protocol requires it + msg: "candidate is not 'rethrows', but protocol requires it" - id: protocol_witness_throws_conflict - msg: >- - candidate throws, but protocol does not allow it + msg: "candidate throws, but protocol does not allow it" - id: protocol_witness_not_objc - msg: >- - candidate is explicitly '@nonobjc' + msg: "candidate is explicitly '@nonobjc'" - id: protocol_witness_enum_case_payload - msg: >- - candidate is an enum case with associated values, but protocol does not - allow it + msg: "candidate is an enum case with associated values, but protocol does not allow it" - id: protocol_witness_type - msg: >- - possibly intended match + msg: "possibly intended match" - id: protocol_witness_nonconform_type - msg: >- - possibly intended match %0 does not %select{inherit from|conform to}2 %1 + msg: "possibly intended match %0 does not %select{inherit from|conform to}2 %1" - id: protocol_witness_circularity - msg: >- - candidate references itself + msg: "candidate references itself" - id: protocol_conformance_here - msg: >- - %select{|class }0%1 declares conformance to protocol %2 here + msg: "%select{|class }0%1 declares conformance to protocol %2 here" - id: declared_protocol_conformance_here - msg: >- - %select{%0 inherits conformance to protocol %2 from superclass|%0 - declares conformance to protocol %2|%0 implicitly conforms to protocol %2 - (via conformance to %3)|%0 implicitly conforms to protocol %2}1 here + msg: "%select{%0 inherits conformance to protocol %2 from superclass|%0 declares conformance to protocol %2|%0 implicitly conforms to protocol %2 (via conformance to %3)|%0 implicitly conforms to protocol %2}1 here" - id: witness_unavailable - msg: >- - unavailable %0 %1 was used to satisfy a requirement of protocol %2 + msg: "unavailable %0 %1 was used to satisfy a requirement of protocol %2" - id: redundant_conformance - msg: >- - redundant conformance of %0 to protocol %1 + msg: "redundant conformance of %0 to protocol %1" - id: redundant_conformance_conditional - msg: >- - conflicting conformance of %0 to protocol %1; there cannot be more than - one conformance, even with different conditional bounds + msg: "conflicting conformance of %0 to protocol %1; there cannot be more than one conformance, even with different conditional bounds" - id: redundant_conformance_adhoc - msg: >- - conformance of %0 to protocol %1 was already stated in - %select{the protocol's|the type's}2 module %3 + msg: "conformance of %0 to protocol %1 was already stated in %select{the protocol's|the type's}2 module %3" - id: redundant_conformance_adhoc_conditional - msg: >- - conformance of %0 to protocol %1 conflicts with that stated in - %select{the protocol's|the type's}2 module %3 and will be ignored; - there cannot be more than one conformance, - even with different conditional bounds + msg: "conformance of %0 to protocol %1 conflicts with that stated in %select{the protocol's|the type's}2 module %3 and will be ignored; there cannot be more than one conformance, even with different conditional bounds" - id: redundant_conformance_witness_ignored - msg: >- - %0 %1 will not be used to satisfy the conformance to %2 + msg: "%0 %1 will not be used to satisfy the conformance to %2" - id: req_near_match - msg: >- - %0 %1 nearly matches %select{defaulted|optional}2 requirement %3 of - protocol %4 + msg: "%0 %1 nearly matches %select{defaulted|optional}2 requirement %3 of protocol %4" - id: optional_req_nonobjc_near_match_add_objc - msg: >- - add '@objc' to provide an Objective-C entrypoint + msg: "add '@objc' to provide an Objective-C entrypoint" - id: req_near_match_move - msg: >- - move %0 to %select{an|another}1 extension to silence this warning + msg: "move %0 to %select{an|another}1 extension to silence this warning" - id: req_near_match_nonobjc - msg: >- - add '@nonobjc' to silence this %select{warning|error}0 + msg: "add '@nonobjc' to silence this %select{warning|error}0" - id: req_near_match_access - msg: >- - make %0 %select{ERROR|private|private|non-public|non-public}1 to silence - this warning + msg: "make %0 %select{ERROR|private|private|non-public|non-public}1 to silence this warning" - id: missing_append_interpolation - msg: >- - type conforming to 'StringInterpolationProtocol' does not implement a - valid 'appendInterpolation' method + msg: "type conforming to 'StringInterpolationProtocol' does not implement a valid 'appendInterpolation' method" - id: append_interpolation_static - msg: >- - 'appendInterpolation' method will never be used because it is static + msg: "'appendInterpolation' method will never be used because it is static" - id: append_interpolation_void_or_discardable - msg: >- - 'appendInterpolation' method does not return 'Void' or have a discardable - result + msg: "'appendInterpolation' method does not return 'Void' or have a discardable result" - id: append_interpolation_access_control - msg: >- - 'appendInterpolation' method is - %select{private|fileprivate|internal|public|open}0, but %1 is - %select{private|fileprivate|internal|public|open}2 + msg: "'appendInterpolation' method is %select{private|fileprivate|internal|public|open}0, but %1 is %select{private|fileprivate|internal|public|open}2" - id: assoc_type_outside_of_protocol - msg: >- - associated type %0 can only be used with a concrete type or generic - parameter base + msg: "associated type %0 can only be used with a concrete type or generic parameter base" - id: typealias_outside_of_protocol - msg: >- - type alias %0 can only be used with a concrete type or generic parameter - base + msg: "type alias %0 can only be used with a concrete type or generic parameter base" - id: objc_protocol_inherits_non_objc_protocol - msg: >- - @objc protocol %0 cannot refine non-@objc protocol %1 + msg: "@objc protocol %0 cannot refine non-@objc protocol %1" - id: protocol_where_clause_self_requirement - msg: >- - constraint with subject type of 'Self' is not supported; consider adding - requirement to protocol inheritance clause instead + msg: "constraint with subject type of 'Self' is not supported; consider adding requirement to protocol inheritance clause instead" - id: invalid_protocol_composition_member - msg: >- - non-protocol, non-class type %0 cannot be used within a - protocol-constrained type + msg: "non-protocol, non-class type %0 cannot be used within a protocol-constrained type" - id: protocol_composition_one_class - msg: >- - protocol-constrained type cannot contain class %0 because it already - contains class %1 + msg: "protocol-constrained type cannot contain class %0 because it already contains class %1" - id: requires_conformance_nonprotocol - msg: >- - type %0 constrained to non-protocol, non-class type %1 + msg: "type %0 constrained to non-protocol, non-class type %1" - id: requires_conformance_nonprotocol_fixit - msg: >- - use '%0 == %1' to require '%0' to be '%1' + msg: "use '%0 == %1' to require '%0' to be '%1'" - id: requires_not_suitable_archetype - msg: >- - type %0 in conformance requirement does not refer to a generic parameter - or associated type + msg: "type %0 in conformance requirement does not refer to a generic parameter or associated type" - id: requires_no_same_type_archetype - msg: >- - neither type in same-type constraint (%0 or %1) refers to a generic - parameter or associated type + msg: "neither type in same-type constraint (%0 or %1) refers to a generic parameter or associated type" - id: requires_generic_params_made_equal - msg: >- - same-type requirement makes generic parameters %0 and %1 equivalent + msg: "same-type requirement makes generic parameters %0 and %1 equivalent" - id: requires_generic_param_made_equal_to_concrete - msg: >- - same-type requirement makes generic parameter %0 non-generic + msg: "same-type requirement makes generic parameter %0 non-generic" - id: recursive_decl_reference - msg: >- - %0 %1 references itself + msg: "%0 %1 references itself" - id: recursive_same_type_constraint - msg: >- - same-type constraint %0 == %1 is recursive + msg: "same-type constraint %0 == %1 is recursive" - id: recursive_superclass_constraint - msg: >- - superclass constraint %0 : %1 is recursive + msg: "superclass constraint %0 : %1 is recursive" - id: requires_generic_param_same_type_does_not_conform - msg: >- - same-type constraint type %0 does not conform to required protocol %1 + msg: "same-type constraint type %0 does not conform to required protocol %1" - id: requires_same_concrete_type - msg: >- - generic signature requires types %0 and %1 to be the same + msg: "generic signature requires types %0 and %1 to be the same" - id: redundant_conformance_constraint - msg: >- - redundant conformance constraint %0: %1 + msg: "redundant conformance constraint %0: %1" - id: redundant_conformance_here - msg: >- - conformance constraint %1: %2 %select{written here|implied here|inferred - from type here}0 + msg: "conformance constraint %1: %2 %select{written here|implied here|inferred from type here}0" - id: unsupported_recursive_requirements - msg: >- - requirement involves recursion that is not currently supported + msg: "requirement involves recursion that is not currently supported" - id: same_type_conflict - msg: >- - %select{generic parameter |protocol |}0%1 cannot be equal to both %2 and %3 + msg: "%select{generic parameter |protocol |}0%1 cannot be equal to both %2 and %3" - id: redundant_same_type_to_concrete - msg: >- - redundant same-type constraint %0 == %1 + msg: "redundant same-type constraint %0 == %1" - id: same_type_redundancy_here - msg: >- - same-type constraint %1 == %2 %select{written here|implied here|inferred - from type here}0 + msg: "same-type constraint %1 == %2 %select{written here|implied here|inferred from type here}0" - id: requires_superclass_conflict - msg: >- - %select{generic parameter %1 cannot|protocol %1 cannot require 'Self' - to|%1 cannot}0 be a subclass of both %2 and %3 + msg: "%select{generic parameter %1 cannot|protocol %1 cannot require 'Self' to|%1 cannot}0 be a subclass of both %2 and %3" - id: redundant_superclass_constraint - msg: >- - redundant superclass constraint %0 : %1 + msg: "redundant superclass constraint %0 : %1" - id: superclass_redundancy_here - msg: >- - superclass constraint %1 : %2 %select{written here|implied here|inferred - from type here}0 + msg: "superclass constraint %1 : %2 %select{written here|implied here|inferred from type here}0" - id: conflicting_layout_constraints - msg: >- - %select{generic parameter |protocol |}0%1 has conflicting constraints %2 - and %3 + msg: "%select{generic parameter |protocol |}0%1 has conflicting constraints %2 and %3" - id: redundant_layout_constraint - msg: >- - redundant constraint %0 : %1 + msg: "redundant constraint %0 : %1" - id: previous_layout_constraint - msg: >- - constraint %1 : %2 %select{written here|implied here|inferred from type - here}0 + msg: "constraint %1 : %2 %select{written here|implied here|inferred from type here}0" - id: redundant_same_type_constraint - msg: >- - redundant same-type constraint %0 == %1 + msg: "redundant same-type constraint %0 == %1" - id: previous_same_type_constraint - msg: >- - previous same-type constraint %1 == %2 %select{written here|implied - here|inferred from type here}0 + msg: "previous same-type constraint %1 == %2 %select{written here|implied here|inferred from type here}0" - id: inherited_associated_type_redecl - msg: >- - redeclaration of associated type %0 from protocol %1 is better expressed - as a 'where' clause on the protocol + msg: "redeclaration of associated type %0 from protocol %1 is better expressed as a 'where' clause on the protocol" - id: typealias_override_associated_type - msg: >- - typealias overriding associated type %0 from protocol %1 is better - expressed as same-type constraint on the protocol + msg: "typealias overriding associated type %0 from protocol %1 is better expressed as same-type constraint on the protocol" - id: associated_type_override_typealias - msg: >- - associated type %0 is redundant with type %0 declared in inherited %1 %2 + msg: "associated type %0 is redundant with type %0 declared in inherited %1 %2" - id: associated_type_objc - msg: >- - associated type %0 cannot be declared inside '@objc' protocol %1 + msg: "associated type %0 cannot be declared inside '@objc' protocol %1" - id: generic_param_access - msg: >- - %0 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}2}1 because its generic - %select{parameter|requirement}5 uses %select{a private|a fileprivate|an - internal|an '@_spi'|an '@_spi'}3 type + msg: "%0 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}2}1 because its generic %select{parameter|requirement}5 uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type" - id: generic_param_access_warn - msg: >- - %0 %select{should be declared - %select{private|fileprivate|internal|%error|%error}3|should not be declared - %select{in this context|fileprivate|internal|public|open}2}1 because its generic - %select{parameter|requirement}5 uses %select{a private|a fileprivate|an - internal|an '@_spi'|an '@_spi'}3 type + msg: "%0 %select{should be declared %select{private|fileprivate|internal|%error|%error}3|should not be declared %select{in this context|fileprivate|internal|public|open}2}1 because its generic %select{parameter|requirement}5 uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type" - id: generic_param_usable_from_inline - msg: >- - type referenced from a generic %select{parameter|requirement}1 of a - '@usableFromInline' %0 must be '@usableFromInline' or public + msg: "type referenced from a generic %select{parameter|requirement}1 of a '@usableFromInline' %0 must be '@usableFromInline' or public" - id: generic_param_usable_from_inline_warn - msg: >- - type referenced from a generic %select{parameter|requirement}1 of a - '@usableFromInline' %0 should be '@usableFromInline' or public + msg: "type referenced from a generic %select{parameter|requirement}1 of a '@usableFromInline' %0 should be '@usableFromInline' or public" - id: override_multiple_decls_base - msg: >- - declaration %0 cannot override more than one superclass declaration + msg: "declaration %0 cannot override more than one superclass declaration" - id: override_multiple_decls_arg_mismatch - msg: >- - declaration %0 has different argument labels from any potential overrides + msg: "declaration %0 has different argument labels from any potential overrides" - id: overridden_near_match_here - msg: >- - potential overridden %0 %1 here + msg: "potential overridden %0 %1 here" - id: override_decl_extension - msg: >- - overriding %select{|non-@objc }0declarations %select{in extensions|from - extensions}0 is not supported + msg: "overriding %select{|non-@objc }0declarations %select{in extensions|from extensions}0 is not supported" - id: overridden_here - msg: >- - overridden declaration is here + msg: "overridden declaration is here" - id: overridden_here_can_be_objc - msg: >- - add '@objc' to make this declaration overridable + msg: "add '@objc' to make this declaration overridable" - id: missing_override - msg: >- - overriding declaration requires an 'override' keyword + msg: "overriding declaration requires an 'override' keyword" - id: missing_override_warn - msg: >- - implicit override should be marked with 'override' or suppressed with - '@_nonoverride' + msg: "implicit override should be marked with 'override' or suppressed with '@_nonoverride'" - id: multiple_override - msg: >- - %0 has already been overridden + msg: "%0 has already been overridden" - id: multiple_override_prev - msg: >- - %0 previously overridden here + msg: "%0 previously overridden here" - id: override_unavailable - msg: >- - cannot override %0 which has been marked unavailable%select{|: %1}1 + msg: "cannot override %0 which has been marked unavailable%select{|: %1}1" - id: suggest_removing_override - msg: >- - remove 'override' modifier to declare a new %0 + msg: "remove 'override' modifier to declare a new %0" - id: override_less_available - msg: >- - overriding %0 must be as available as declaration it overrides + msg: "overriding %0 must be as available as declaration it overrides" - id: override_accessor_less_available - msg: >- - overriding %0 for %1 must be as available as declaration it overrides + msg: "overriding %0 for %1 must be as available as declaration it overrides" - id: override_let_property - msg: >- - cannot override immutable 'let' property %0 with the getter of a 'var' + msg: "cannot override immutable 'let' property %0 with the getter of a 'var'" - id: override_not_accessible - msg: >- - %select{|setter of }0overriding %1 must be as accessible as %select{its - enclosing type|the declaration it overrides}2 + msg: "%select{|setter of }0overriding %1 must be as accessible as %select{its enclosing type|the declaration it overrides}2" - id: override_of_non_open - msg: >- - overriding non-open %0 outside of its defining module + msg: "overriding non-open %0 outside of its defining module" - id: method_does_not_override - msg: >- - method does not override any method from its %select{parent protocol|superclass}0 + msg: "method does not override any method from its %select{parent protocol|superclass}0" - id: property_does_not_override - msg: >- - property does not override any property from its %select{parent protocol|superclass}0 + msg: "property does not override any property from its %select{parent protocol|superclass}0" - id: subscript_does_not_override - msg: >- - subscript does not override any subscript from its %select{parent protocol|superclass}0 + msg: "subscript does not override any subscript from its %select{parent protocol|superclass}0" - id: initializer_does_not_override - msg: >- - initializer does not override a designated initializer from its - %select{parent protocol|superclass}0 + msg: "initializer does not override a designated initializer from its %select{parent protocol|superclass}0" - id: failable_initializer_override - msg: >- - failable initializer %0 cannot override a non-failable initializer + msg: "failable initializer %0 cannot override a non-failable initializer" - id: nonfailable_initializer_override_here - msg: >- - non-failable initializer %0 overridden here + msg: "non-failable initializer %0 overridden here" - id: property_override_here - msg: >- - attempt to override property here + msg: "attempt to override property here" - id: subscript_override_here - msg: >- - attempt to override subscript here + msg: "attempt to override subscript here" - id: convenience_init_override_here - msg: >- - attempt to override convenience initializer here + msg: "attempt to override convenience initializer here" - id: override_type_mismatch_with_fixits - msg: >- - type does not match superclass %0 with type %1 + msg: "type does not match superclass %0 with type %1" - id: override_type_mismatch_with_fixits_init - msg: >- - type does not match superclass initializer with %select{no - arguments|argument %1|arguments %1}0 + msg: "type does not match superclass initializer with %select{no arguments|argument %1|arguments %1}0" - id: override_nonclass_decl - msg: >- - 'override' can only be specified on class members + msg: "'override' can only be specified on class members" - id: nonoverride_wrong_decl_context - msg: >- - '@_nonoverride' can only be specified on class or protocol members + msg: "'@_nonoverride' can only be specified on class or protocol members" - id: nonoverride_and_override_attr - msg: >- - 'override' cannot be combined with '@_nonoverride' + msg: "'override' cannot be combined with '@_nonoverride'" - id: override_property_type_mismatch - msg: >- - property %0 with type %1 cannot override a property with type %2 + msg: "property %0 with type %1 cannot override a property with type %2" - id: override_with_stored_property - msg: >- - cannot override with a stored property %0 + msg: "cannot override with a stored property %0" - id: override_with_stored_property_warn - msg: >- - cannot override with a stored property %0 + msg: "cannot override with a stored property %0" - id: observing_readonly_property - msg: >- - cannot observe read-only property %0; it can't change + msg: "cannot observe read-only property %0; it can't change" - id: override_mutable_with_readonly_property - msg: >- - cannot override mutable property with read-only property %0 + msg: "cannot override mutable property with read-only property %0" - id: override_argument_name_mismatch - msg: >- - argument labels for %select{method|initializer}0 %1 do not match those of - overridden %select{method|initializer}0 %2 + msg: "argument labels for %select{method|initializer}0 %1 do not match those of overridden %select{method|initializer}0 %2" - id: override_ownership_mismatch - msg: >- - cannot override %0 property with %1 property + msg: "cannot override %0 property with %1 property" - id: override_dynamic_self_mismatch - msg: >- - cannot override a Self return type with a non-Self return type + msg: "cannot override a Self return type with a non-Self return type" - id: override_class_declaration_in_extension - msg: >- - cannot override a non-dynamic class declaration from an extension + msg: "cannot override a non-dynamic class declaration from an extension" - id: override_throws - msg: >- - cannot override non-throwing %select{method|initializer}0 with throwing - %select{method|initializer}0 + msg: "cannot override non-throwing %select{method|initializer}0 with throwing %select{method|initializer}0" - id: override_throws_objc - msg: >- - overriding a throwing @objc %select{method|initializer}0 with a - non-throwing %select{method|initializer}0 is not supported + msg: "overriding a throwing @objc %select{method|initializer}0 with a non-throwing %select{method|initializer}0 is not supported" - id: satisfy_throws_objc - msg: >- - satisfying a throwing @objc %select{method|initializer}0 with a - non-throwing %select{method|initializer}0 is not supported + msg: "satisfying a throwing @objc %select{method|initializer}0 with a non-throwing %select{method|initializer}0 is not supported" - id: override_optional_mismatch - msg: >- - cannot override %0 %select{parameter|index}1 of type %2 with non-optional - type %3 + msg: "cannot override %0 %select{parameter|index}1 of type %2 with non-optional type %3" - id: override_optional_result_mismatch - msg: >- - cannot override %0 %select{result|element}1 type %2 with optional type %3 + msg: "cannot override %0 %select{result|element}1 type %2 with optional type %3" - id: override_unnecessary_IUO - msg: >- - overriding %0 parameter of type %1 with implicitly unwrapped optional - type %2 + msg: "overriding %0 parameter of type %1 with implicitly unwrapped optional type %2" - id: override_unnecessary_result_IUO - msg: >- - overriding %0 optional result type %1 with implicitly unwrapped optional - type %2 + msg: "overriding %0 optional result type %1 with implicitly unwrapped optional type %2" - id: override_unnecessary_IUO_remove - msg: >- - remove '!' to make the parameter required + msg: "remove '!' to make the parameter required" - id: override_unnecessary_IUO_use_strict - msg: >- - use '?' to make the result optional + msg: "use '?' to make the result optional" - id: override_unnecessary_IUO_silence - msg: >- - add parentheses to silence this warning + msg: "add parentheses to silence this warning" - id: override_mutable_covariant_property - msg: >- - cannot override mutable property %0 of type %1 with covariant type %2 + msg: "cannot override mutable property %0 of type %1 with covariant type %2" - id: override_mutable_covariant_subscript - msg: >- - cannot override mutable subscript of type %0 with covariant type %1 + msg: "cannot override mutable subscript of type %0 with covariant type %1" - id: static_decl_already_final - msg: >- - static declarations are already final + msg: "static declarations are already final" - id: open_decl_cannot_be_final - msg: >- - %0 cannot be declared both 'final' and 'open' + msg: "%0 cannot be declared both 'final' and 'open'" - id: implicitly_final_cannot_be_open - msg: >- - %select{'let' properties|members of 'final' classes|static declarations}0 - are implicitly 'final'; use 'public' instead of 'open' + msg: "%select{'let' properties|members of 'final' classes|static declarations}0 are implicitly 'final'; use 'public' instead of 'open'" - id: implicitly_final_cannot_be_open_swift4 - msg: >- - %select{'let' properties|members of 'final' classes|static declarations}0 - are implicitly 'final'; use 'public' instead of 'open' + msg: "%select{'let' properties|members of 'final' classes|static declarations}0 are implicitly 'final'; use 'public' instead of 'open'" - id: override_swift3_objc_inference - msg: >- - override of %0 %1 from extension of %2 depends on deprecated inference of - '@objc' + msg: "override of %0 %1 from extension of %2 depends on deprecated inference of '@objc'" - id: override_method_different_generic_sig - msg: >- - overridden method %0 has generic signature %1 which is incompatible with - base method's generic signature %2; expected generic signature to be %3 + msg: "overridden method %0 has generic signature %1 which is incompatible with base method's generic signature %2; expected generic signature to be %3" - id: duplicate_inheritance - msg: >- - duplicate inheritance from %0 + msg: "duplicate inheritance from %0" - id: duplicate_anyobject_class_inheritance - msg: >- - redundant inheritance from 'AnyObject' and Swift 3 'class' keyword + msg: "redundant inheritance from 'AnyObject' and Swift 3 'class' keyword" - id: inheritance_from_protocol_with_superclass - msg: >- - inheritance from class-constrained protocol composition type %0 + msg: "inheritance from class-constrained protocol composition type %0" - id: multiple_inheritance - msg: >- - multiple inheritance from classes %0 and %1 + msg: "multiple inheritance from classes %0 and %1" - id: inheritance_from_non_protocol_or_class - msg: >- - inheritance from non-protocol, non-class type %0 + msg: "inheritance from non-protocol, non-class type %0" - id: inheritance_from_non_protocol - msg: >- - inheritance from non-protocol type %0 + msg: "inheritance from non-protocol type %0" - id: superclass_not_first - msg: >- - superclass %0 must appear first in the inheritance clause + msg: "superclass %0 must appear first in the inheritance clause" - id: superclass_not_open - msg: >- - cannot inherit from non-open class %0 outside of its defining module + msg: "cannot inherit from non-open class %0 outside of its defining module" - id: superclass_here - msg: >- - superclass is declared here + msg: "superclass is declared here" - id: superclass_of_open_not_open - msg: >- - superclass %0 of open class must be open + msg: "superclass %0 of open class must be open" - id: inheritance_from_final_class - msg: >- - inheritance from a final class %0 + msg: "inheritance from a final class %0" - id: inheritance_from_unspecialized_objc_generic_class - msg: >- - inheritance from a generic Objective-C class %0 must bind type parameters - of %0 to specific concrete types + msg: "inheritance from a generic Objective-C class %0 must bind type parameters of %0 to specific concrete types" - id: inheritance_from_class_with_missing_vtable_entries - msg: >- - cannot inherit from class %0 because it has overridable members that - could not be loaded + msg: "cannot inherit from class %0 because it has overridable members that could not be loaded" - id: inheritance_from_class_with_missing_vtable_entries_versioned - msg: >- - cannot inherit from class %0 (compiled with Swift %1) because it has - overridable members that could not be loaded in Swift %2 + msg: "cannot inherit from class %0 (compiled with Swift %1) because it has overridable members that could not be loaded in Swift %2" - id: inheritance_from_cf_class - msg: >- - cannot inherit from Core Foundation type %0 + msg: "cannot inherit from Core Foundation type %0" - id: inheritance_from_objc_runtime_visible_class - msg: >- - cannot inherit from class %0 because it is only visible via the - Objective-C runtime + msg: "cannot inherit from class %0 because it is only visible via the Objective-C runtime" - id: enum_case_access - msg: >- - enum case in %select{a private|a fileprivate|an internal|a - public|%error}0 enum uses %select{a private|a fileprivate|an - internal|%error|%error}1 type + msg: "enum case in %select{a private|a fileprivate|an internal|a public|%error}0 enum uses %select{a private|a fileprivate|an internal|%error|%error}1 type" - id: enum_case_access_warn - msg: >- - enum case in %select{a private|a fileprivate|an internal|a - public|%error}0 enum uses %select{a private|a fileprivate|an - internal|%error|%error}1 type + msg: "enum case in %select{a private|a fileprivate|an internal|a public|%error}0 enum uses %select{a private|a fileprivate|an internal|%error|%error}1 type" - id: enum_case_usable_from_inline - msg: >- - type of enum case in '@usableFromInline' enum must be '@usableFromInline' - or public + msg: "type of enum case in '@usableFromInline' enum must be '@usableFromInline' or public" - id: enum_case_usable_from_inline_warn - msg: >- - type of enum case in '@usableFromInline' enum should be - '@usableFromInline' or public + msg: "type of enum case in '@usableFromInline' enum should be '@usableFromInline' or public" - id: enum_stored_property - msg: >- - enums must not contain stored properties + msg: "enums must not contain stored properties" - id: multiple_enum_raw_types - msg: >- - multiple enum raw types %0 and %1 + msg: "multiple enum raw types %0 and %1" - id: raw_type_not_first - msg: >- - raw type %0 must appear first in the enum inheritance clause + msg: "raw type %0 must appear first in the enum inheritance clause" - id: raw_type_not_literal_convertible - msg: >- - raw type %0 is not expressible by a string, integer, or floating-point - literal + msg: "raw type %0 is not expressible by a string, integer, or floating-point literal" - id: enum_raw_type_not_equatable - msg: >- - RawRepresentable conformance cannot be synthesized because raw type %0 is - not Equatable + msg: "RawRepresentable conformance cannot be synthesized because raw type %0 is not Equatable" - id: enum_raw_type_nonconforming_and_nonsynthable - msg: >- - %0 declares raw type %1, but does not conform to RawRepresentable and - conformance could not be synthesized + msg: "%0 declares raw type %1, but does not conform to RawRepresentable and conformance could not be synthesized" - id: enum_declares_rawrep_with_raw_type - msg: >- - %0 declares raw type %1, which implies RawRepresentable + msg: "%0 declares raw type %1, which implies RawRepresentable" - id: enum_raw_type_access - msg: >- - enum %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}3|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its raw type uses - %select{a private|a fileprivate|an internal|%error|%error}2 type + msg: "enum %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}3|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its raw type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - id: enum_raw_type_access_warn - msg: >- - enum %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its raw - type uses %select{a private|a fileprivate|an internal|%error|%error}2 type + msg: "enum %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its raw type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - id: enum_raw_type_not_usable_from_inline - msg: >- - type referenced from the raw type of a '@usableFromInline' enum must be - '@usableFromInline' or public + msg: "type referenced from the raw type of a '@usableFromInline' enum must be '@usableFromInline' or public" - id: enum_raw_type_not_usable_from_inline_warn - msg: >- - type referenced from the raw type of a '@usableFromInline' enum should be - '@usableFromInline' or public + msg: "type referenced from the raw type of a '@usableFromInline' enum should be '@usableFromInline' or public" - id: empty_enum_raw_type - msg: >- - an enum with no cases cannot declare a raw type + msg: "an enum with no cases cannot declare a raw type" - id: enum_raw_value_without_raw_type - msg: >- - enum case cannot have a raw value if the enum does not have a raw type + msg: "enum case cannot have a raw value if the enum does not have a raw type" - id: enum_with_raw_type_case_with_argument - msg: >- - enum with raw type cannot have cases with arguments + msg: "enum with raw type cannot have cases with arguments" - id: enum_raw_type_here - msg: >- - declared raw type %0 here + msg: "declared raw type %0 here" - id: objc_enum_no_raw_type - msg: >- - '@objc' enum must declare an integer raw type + msg: "'@objc' enum must declare an integer raw type" - id: objc_enum_raw_type_not_integer - msg: >- - '@objc' enum raw type %0 is not an integer type + msg: "'@objc' enum raw type %0 is not an integer type" - id: enum_non_integer_raw_value_auto_increment - msg: >- - enum case must declare a raw value when the preceding raw value is not an - integer + msg: "enum case must declare a raw value when the preceding raw value is not an integer" - id: enum_non_integer_convertible_raw_type_no_value - msg: >- - enum cases require explicit raw values when the raw type is not - expressible by integer or string literal + msg: "enum cases require explicit raw values when the raw type is not expressible by integer or string literal" - id: enum_raw_value_not_unique - msg: >- - raw value for enum case is not unique + msg: "raw value for enum case is not unique" - id: enum_raw_value_magic_literal - msg: >- - use of '%0' literal as raw value for enum case is not supported + msg: "use of '%0' literal as raw value for enum case is not supported" - id: enum_raw_value_used_here - msg: >- - raw value previously used here + msg: "raw value previously used here" - id: enum_raw_value_incrementing_from_here - msg: >- - raw value auto-incremented from here + msg: "raw value auto-incremented from here" - id: enum_raw_value_incrementing_from_zero - msg: >- - raw value implicitly auto-incremented from zero + msg: "raw value implicitly auto-incremented from zero" - id: construct_raw_representable_from_unwrapped_value - msg: >- - construct %0 from unwrapped %1 value + msg: "construct %0 from unwrapped %1 value" - id: decl_from_hidden_module - msg: >- - cannot use %0 %1 %select{here|as property wrapper here|in an extension - with public or '@usableFromInline' members|in an extension with conditional - conformances}2; %select{%3 has been imported as implementation-only|it - is an SPI imported from %3|it is SPI}4 + msg: "cannot use %0 %1 %select{here|as property wrapper here|in an extension with public or '@usableFromInline' members|in an extension with conditional conformances}2; %select{%3 has been imported as implementation-only|it is an SPI imported from %3|it is SPI}4" + +- id: decl_from_hidden_module_warn + msg: "cannot use %0 %1 %select{in SPI|as property wrapper in SPI|in an extension with public or '@usableFromInline' members|in an extension with conditional conformances}2; %select{%3 has been imported as implementation-only}4" - id: conformance_from_implementation_only_module - msg: >- - cannot use conformance of %0 to %1 %select{here|as property wrapper - here|in an extension with public or '@usableFromInline' members|in - an extension with conditional conformances}2; - %3 has been imported as implementation-only + msg: "cannot use conformance of %0 to %1 %select{here|as property wrapper here|in an extension with public or '@usableFromInline' members|in an extension with conditional conformances}2; %3 has been imported as implementation-only" - id: assoc_conformance_from_implementation_only_module - msg: >- - cannot use conformance of %0 to %1 in associated type %3 (inferred as - %4); %2 has been imported as implementation-only + msg: "cannot use conformance of %0 to %1 in associated type %3 (inferred as %4); %2 has been imported as implementation-only" - id: unexportable_clang_function_type - msg: >- - cannot export the underlying C type of the function type %0; it may use - anonymous types or types defined outside of a module + msg: "cannot export the underlying C type of the function type %0; it may use anonymous types or types defined outside of a module" - id: warn_implementation_only_conflict - msg: >- - %0 inconsistently imported as implementation-only + msg: "%0 inconsistently imported as implementation-only" - id: implementation_only_conflict_here - msg: >- - imported as implementation-only here + msg: "imported as implementation-only here" - id: implementation_only_decl_non_override - msg: >- - '@_implementationOnly' can only be used on overrides + msg: "'@_implementationOnly' can only be used on overrides" - id: implementation_only_override_changed_type - msg: >- - '@_implementationOnly' override must have the same type as the - declaration it overrides (%0) + msg: "'@_implementationOnly' override must have the same type as the declaration it overrides (%0)" - id: implementation_only_override_without_attr - msg: >- - override of '@_implementationOnly' %0 should also be declared - '@_implementationOnly' + msg: "override of '@_implementationOnly' %0 should also be declared '@_implementationOnly'" - id: implementation_only_override_import_without_attr - msg: >- - override of %0 imported as implementation-only must be declared - '@_implementationOnly' + msg: "override of %0 imported as implementation-only must be declared '@_implementationOnly'" - id: cannot_synthesize_init_in_extension_of_nonfinal - msg: >- - implementation of %0 for non-final class cannot be automatically - synthesized in extension because initializer requirement %1 can only be - satisfied by a 'required' initializer in the class definition + msg: "implementation of %0 for non-final class cannot be automatically synthesized in extension because initializer requirement %1 can only be satisfied by a 'required' initializer in the class definition" - id: cannot_synthesize_in_crossfile_extension - msg: >- - extension outside of file declaring %0 %1 prevents automatic synthesis - of %2 for protocol %3 + msg: "extension outside of file declaring %0 %1 prevents automatic synthesis of %2 for protocol %3" - id: broken_additive_arithmetic_requirement - msg: >- - AdditiveArithmetic protocol is broken: unexpected requirement + msg: "AdditiveArithmetic protocol is broken: unexpected requirement" - id: broken_case_iterable_requirement - msg: >- - CaseIterable protocol is broken: unexpected requirement + msg: "CaseIterable protocol is broken: unexpected requirement" - id: broken_raw_representable_requirement - msg: >- - RawRepresentable protocol is broken: unexpected requirement + msg: "RawRepresentable protocol is broken: unexpected requirement" - id: broken_comparable_requirement - msg: >- - Comparable protocol is broken: unexpected requirement + msg: "Comparable protocol is broken: unexpected requirement" - id: broken_equatable_requirement - msg: >- - Equatable protocol is broken: unexpected requirement + msg: "Equatable protocol is broken: unexpected requirement" - id: broken_hashable_requirement - msg: >- - Hashable protocol is broken: unexpected requirement + msg: "Hashable protocol is broken: unexpected requirement" - id: broken_hashable_no_hasher - msg: >- - Hashable protocol is broken: Hasher type not found + msg: "Hashable protocol is broken: Hasher type not found" - id: broken_errortype_requirement - msg: >- - Error protocol is broken: unexpected requirement + msg: "Error protocol is broken: unexpected requirement" - id: broken_int_hashable_conformance - msg: >- - Int type is broken: does not conform to Hashable + msg: "Int type is broken: does not conform to Hashable" - id: broken_int_integer_literal_convertible_conformance - msg: >- - Int type is broken: does not conform to ExpressibleByIntegerLiteral + msg: "Int type is broken: does not conform to ExpressibleByIntegerLiteral" - id: no_less_than_overload_for_int - msg: >- - no overload of '<' for Int + msg: "no overload of '<' for Int" - id: no_equal_overload_for_int - msg: >- - no overload of '==' for Int + msg: "no overload of '==' for Int" - id: broken_coding_key_requirement - msg: >- - CodingKey protocol is broken: unexpected requirement + msg: "CodingKey protocol is broken: unexpected requirement" - id: broken_encodable_requirement - msg: >- - Encodable protocol is broken: unexpected requirement + msg: "Encodable protocol is broken: unexpected requirement" - id: broken_decodable_requirement - msg: >- - Decodable protocol is broken: unexpected requirement + msg: "Decodable protocol is broken: unexpected requirement" - id: broken_differentiable_requirement - msg: >- - Differentiable protocol is broken: unexpected requirement + msg: "Differentiable protocol is broken: unexpected requirement" - id: differentiable_nondiff_type_implicit_noderivative_fixit - msg: >- - stored property %0 has no derivative because %1 does not conform to - 'Differentiable'; add an explicit '@noDerivative' attribute%select{|, - or conform %2 to 'AdditiveArithmetic'}3 + msg: "stored property %0 has no derivative because %1 does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute%select{|, or conform %2 to 'AdditiveArithmetic'}3" - id: differentiable_immutable_wrapper_implicit_noderivative_fixit - msg: >- - synthesis of the 'Differentiable.move(along:)' requirement for %1 - requires 'wrappedValue' in property wrapper %0 to be mutable; - add an explicit '@noDerivative' attribute%select{|, - or conform %1 to 'AdditiveArithmetic'}2 + msg: "synthesis of the 'Differentiable.move(along:)' requirement for %1 requires 'wrappedValue' in property wrapper %0 to be mutable; add an explicit '@noDerivative' attribute%select{|, or conform %1 to 'AdditiveArithmetic'}2" - id: differentiable_let_property_implicit_noderivative_fixit - msg: >- - synthesis of the 'Differentiable.move(along:)' requirement for %0 - requires all stored properties not marked with `@noDerivative` - to be mutable; use 'var' instead, or add an explicit - '@noDerivative' attribute%select{|, or conform %0 to 'AdditiveArithmetic'}1 + msg: "synthesis of the 'Differentiable.move(along:)' requirement for %0 requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute%select{|, or conform %0 to 'AdditiveArithmetic'}1" - id: codable_extraneous_codingkey_case_here - msg: >- - CodingKey case %0 does not match any stored properties + msg: "CodingKey case %0 does not match any stored properties" - id: codable_non_conforming_property_here - msg: >- - cannot automatically synthesize %0 because %1 does not conform to %0 + msg: "cannot automatically synthesize %0 because %1 does not conform to %0" - id: codable_non_decoded_property_here - msg: >- - cannot automatically synthesize %0 because %1 does not have a matching - CodingKey and does not have a default value + msg: "cannot automatically synthesize %0 because %1 does not have a matching CodingKey and does not have a default value" - id: codable_codingkeys_type_is_not_an_enum_here - msg: >- - cannot automatically synthesize %0 because 'CodingKeys' is not an enum + msg: "cannot automatically synthesize %0 because 'CodingKeys' is not an enum" - id: codable_codingkeys_type_does_not_conform_here - msg: >- - cannot automatically synthesize %0 because 'CodingKeys' does not conform - to CodingKey + msg: "cannot automatically synthesize %0 because 'CodingKeys' does not conform to CodingKey" - id: decodable_no_super_init_here - msg: >- - cannot automatically synthesize %0 because superclass does not have a - callable %1 + msg: "cannot automatically synthesize %0 because superclass does not have a callable %1" - id: decodable_super_init_not_designated_here - msg: >- - cannot automatically synthesize %0 because implementation would need to - call %1, which is not designated + msg: "cannot automatically synthesize %0 because implementation would need to call %1, which is not designated" - id: decodable_inaccessible_super_init_here - msg: >- - cannot automatically synthesize %0 because implementation would need to - call %1, which is inaccessible due to - '%select{private|fileprivate|internal|%error|%error}2' protection level + msg: "cannot automatically synthesize %0 because implementation would need to call %1, which is inaccessible due to '%select{private|fileprivate|internal|%error|%error}2' protection level" - id: decodable_super_init_is_failable_here - msg: >- - cannot automatically synthesize %0 because implementation would need to - call %1, which is failable + msg: "cannot automatically synthesize %0 because implementation would need to call %1, which is failable" - id: decodable_suggest_overriding_init_here - msg: >- - did you mean to override 'init(from:)'? + msg: "did you mean to override 'init(from:)'?" - id: codable_suggest_overriding_init_here - msg: >- - did you mean to override 'init(from:)' and 'encode(to:)'? + msg: "did you mean to override 'init(from:)' and 'encode(to:)'?" - id: decodable_property_will_not_be_decoded - msg: >- - immutable property will not be decoded because it is declared with an - initial value which cannot be overwritten + msg: "immutable property will not be decoded because it is declared with an initial value which cannot be overwritten" - id: decodable_property_init_or_codingkeys_implicit - msg: >- - set the initial value via the initializer or explicitly define a - CodingKeys enum %select{including|without}0 a %1 - case to silence this warning + msg: "set the initial value via the initializer or explicitly define a CodingKeys enum %select{including|without}0 a %1 case to silence this warning" - id: decodable_property_init_or_codingkeys_explicit - msg: >- - set the initial value via the initializer or remove the %0 case from the - CodingKeys enum to silence this warning + msg: "set the initial value via the initializer or remove the %0 case from the CodingKeys enum to silence this warning" - id: decodable_make_property_mutable - msg: >- - make the property mutable instead + msg: "make the property mutable instead" - id: missing_member_type_conformance_prevents_synthesis - msg: >- - %select{associated value|stored property}0 type %1 does not conform to - protocol %2, preventing synthesized conformance of %3 to %2 + msg: "%select{associated value|stored property}0 type %1 does not conform to protocol %2, preventing synthesized conformance of %3 to %2" - id: automatic_protocol_synthesis_unsupported - msg: >- - automatic synthesis of '%0' is not supported for %select{classes|structs}1 + msg: "automatic synthesis of '%0' is not supported for %select{classes|structs}1" - id: comparable_synthesis_raw_value_not_allowed - msg: >- - enum declares raw type %0, preventing synthesized conformance of %1 to %2 + msg: "enum declares raw type %0, preventing synthesized conformance of %1 to %2" - id: dynamic_self_non_method - msg: >- - %select{global|local}0 function cannot return 'Self' + msg: "%select{global|local}0 function cannot return 'Self'" - id: dynamic_self_invalid - msg: >- - covariant 'Self' can only appear as the type of a property, subscript or - method result; did you mean '%0'? + msg: "covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean '%0'?" - id: dynamic_self_in_mutable_property - msg: >- - mutable property cannot have covariant 'Self' type + msg: "mutable property cannot have covariant 'Self' type" - id: dynamic_self_in_stored_property - msg: >- - stored property cannot have covariant 'Self' type + msg: "stored property cannot have covariant 'Self' type" - id: dynamic_self_in_mutable_subscript - msg: >- - mutable subscript cannot have covariant 'Self' type + msg: "mutable subscript cannot have covariant 'Self' type" - id: dynamic_self_invalid_property - msg: >- - covariant 'Self' can only appear at the top level of property type + msg: "covariant 'Self' can only appear at the top level of property type" - id: dynamic_self_invalid_subscript - msg: >- - covariant 'Self' can only appear at the top level of subscript element - type + msg: "covariant 'Self' can only appear at the top level of subscript element type" - id: dynamic_self_invalid_method - msg: >- - covariant 'Self' can only appear at the top level of method result type + msg: "covariant 'Self' can only appear at the top level of method result type" - id: dynamic_self_stored_property_init - msg: >- - covariant 'Self' type cannot be referenced from a stored property - initializer + msg: "covariant 'Self' type cannot be referenced from a stored property initializer" - id: dynamic_self_default_arg - msg: >- - covariant 'Self' type cannot be referenced from a default argument - expression + msg: "covariant 'Self' type cannot be referenced from a default argument expression" - id: attr_only_one_decl_kind - msg: >- - %0 may only be used on '%1' declarations + msg: "%0 may only be used on '%1' declarations" - id: attr_not_on_variadic_parameters - msg: >- - '%0' must not be used on variadic parameters + msg: "'%0' must not be used on variadic parameters" - id: attr_not_on_subscript_parameters - msg: >- - '%0' must not be used on subscript parameters + msg: "'%0' must not be used on subscript parameters" - id: attr_ambiguous_reference_to_decl - msg: >- - ambiguous reference to %0 in '@%1' attribute + msg: "ambiguous reference to %0 in '@%1' attribute" - id: override_final - msg: >- - %0 overrides a 'final' %1 + msg: "%0 overrides a 'final' %1" - id: override_static - msg: >- - cannot override %0 + msg: "cannot override %0" - id: member_cannot_be_final - msg: >- - only classes and class members may be marked with 'final' + msg: "only classes and class members may be marked with 'final'" - id: final_not_allowed_here - msg: >- - 'final' may only be applied to classes, properties, methods, and subscripts + msg: "'final' may only be applied to classes, properties, methods, and subscripts" - id: final_not_on_accessors - msg: >- - 'final' cannot be applied to accessors, it must be put on the - %select{var|let|subscript}0 + msg: "'final' cannot be applied to accessors, it must be put on the %select{var|let|subscript}0" - id: override_rethrows_with_non_rethrows - msg: >- - override of 'rethrows' %select{method|initializer}0 should also be - 'rethrows' + msg: "override of 'rethrows' %select{method|initializer}0 should also be 'rethrows'" - id: rethrows_without_throwing_parameter - msg: >- - 'rethrows' function must take a throwing function argument + msg: "'rethrows' function must take a throwing function argument" - id: autoclosure_function_type - msg: >- - @autoclosure attribute only applies to function types + msg: "@autoclosure attribute only applies to function types" - id: invalid_autoclosure_and_convention_attributes - msg: >- - '@convention(%0)' attribute is not allowed on '@autoclosure' types + msg: "'@convention(%0)' attribute is not allowed on '@autoclosure' types" - id: autoclosure_function_input_nonunit - msg: >- - argument type of @autoclosure parameter must be '()' + msg: "argument type of @autoclosure parameter must be '()'" - id: escaping_non_function_parameter - msg: >- - @escaping attribute may only be used in function parameter position + msg: "@escaping attribute may only be used in function parameter position" - id: escaping_optional_type_argument - msg: >- - closure is already escaping in optional type argument + msg: "closure is already escaping in optional type argument" - id: non_ephemeral_non_pointer_type - msg: >- - @_nonEphemeral attribute only applies to pointer types + msg: "@_nonEphemeral attribute only applies to pointer types" - id: attr_NSManaged_not_instance_member - msg: >- - @NSManaged only allowed on an instance property or method + msg: "@NSManaged only allowed on an instance property or method" - id: attr_NSManaged_not_stored - msg: >- - @NSManaged not allowed on %select{computed|observing|addressed}0 properties + msg: "@NSManaged not allowed on %select{computed|observing|addressed}0 properties" - id: attr_NSManaged_let_property - msg: >- - @NSManaged not allowed on a 'let' property + msg: "@NSManaged not allowed on a 'let' property" - id: attr_NSManaged_initial_value - msg: >- - @NSManaged property cannot have an initial value + msg: "@NSManaged property cannot have an initial value" - id: attr_NSManaged_NSCopying - msg: >- - @NSManaged property cannot also be marked @NSCopying + msg: "@NSManaged property cannot also be marked @NSCopying" - id: attr_NSManaged_method_body - msg: >- - @NSManaged method cannot have a body; it must be provided at runtime + msg: "@NSManaged method cannot have a body; it must be provided at runtime" - id: nscopying_only_on_class_properties - msg: >- - @NSCopying may only be used on properties in classes + msg: "@NSCopying may only be used on properties in classes" - id: nscopying_only_mutable - msg: >- - @NSCopying requires property to be mutable + msg: "@NSCopying requires property to be mutable" - id: nscopying_only_stored_property - msg: >- - @NSCopying is only valid on stored properties + msg: "@NSCopying is only valid on stored properties" - id: nscopying_doesnt_conform - msg: >- - @NSCopying is only valid with types that conform to the NSCopying protocol + msg: "@NSCopying is only valid with types that conform to the NSCopying protocol" - id: attr_ApplicationMain_not_ApplicationDelegate - msg: >- - %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 class must - conform to the %select{'UIApplicationDelegate'|'NSApplicationDelegate'}0 - protocol + msg: "%select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 class must conform to the %select{'UIApplicationDelegate'|'NSApplicationDelegate'}0 protocol" - id: attr_generic_ApplicationMain_not_supported - msg: >- - generic %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 - %select{classes|classes|types}0 are not supported + msg: "generic %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 %select{classes|classes|types}0 are not supported" - id: attr_ApplicationMain_multiple - msg: >- - %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute can - only apply to one %select{class|class|type}0 in a module + msg: "%select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute can only apply to one %select{class|class|type}0 in a module" - id: attr_ApplicationMain_with_script - msg: >- - %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute cannot - be used in a module that contains top-level code + msg: "%select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute cannot be used in a module that contains top-level code" - id: attr_ApplicationMain_script_here - msg: >- - top-level code defined in this source file + msg: "top-level code defined in this source file" - id: attr_MainType_without_main - msg: >- - %0 is annotated with @main and must provide a main static function of - type () -> Void or () throws -> Void. + msg: "%0 is annotated with @main and must provide a main static function of type () -> Void or () throws -> Void." - id: lazy_not_on_let - msg: >- - 'lazy' cannot be used on a let + msg: "'lazy' cannot be used on a let" - id: lazy_not_on_computed - msg: >- - 'lazy' must not be used on a computed property + msg: "'lazy' must not be used on a computed property" - id: lazy_on_already_lazy_global - msg: >- - 'lazy' must not be used on an already-lazy global + msg: "'lazy' must not be used on an already-lazy global" - id: lazy_not_in_protocol - msg: >- - 'lazy' isn't allowed on a protocol requirement + msg: "'lazy' isn't allowed on a protocol requirement" - id: lazy_requires_initializer - msg: >- - lazy properties must have an initializer + msg: "lazy properties must have an initializer" - id: lazy_requires_single_var - msg: >- - 'lazy' cannot destructure an initializer + msg: "'lazy' cannot destructure an initializer" - id: lazy_must_be_property - msg: >- - lazy is only valid for members of a struct or class + msg: "lazy is only valid for members of a struct or class" - id: lazy_not_strong - msg: >- - lazy properties cannot be %0 + msg: "lazy properties cannot be %0" + +- id: lazy_var_storage_access + msg: "access to the underlying storage of a lazy property is not allowed" - id: attr_for_debugger_support_only - msg: >- - @LLDBDebuggerSupport may only be used when debugger support is on + msg: "@LLDBDebuggerSupport may only be used when debugger support is on" - id: implements_attr_protocol_lacks_member - msg: >- - protocol %0 has no member %1 + msg: "protocol %0 has no member %1" - id: implements_attr_non_protocol_type - msg: >- - non-protocol type in @_implements attribute + msg: "non-protocol type in @_implements attribute" - id: implements_attr_protocol_not_conformed_to - msg: >- - containing type %0 does not conform to protocol %1 + msg: "containing type %0 does not conform to protocol %1" - id: differentiable_attr_no_vjp_or_jvp_when_linear - msg: >- - cannot specify 'vjp:' or 'jvp:' for linear functions; use '@transpose' - attribute for transpose registration instead + msg: "cannot specify 'vjp:' or 'jvp:' for linear functions; use '@transpose' attribute for transpose registration instead" - id: differentiable_attr_overload_not_found - msg: >- - %0 does not have expected type %1 + msg: "%0 does not have expected type %1" - id: differentiable_attr_duplicate - msg: >- - duplicate '@differentiable' attribute with same parameters + msg: "duplicate '@differentiable' attribute with same parameters" - id: differentiable_attr_duplicate_note - msg: >- - other attribute declared here + msg: "other attribute declared here" - id: differentiable_attr_function_not_same_type_context - msg: >- - %0 is not defined in the current type context + msg: "%0 is not defined in the current type context" - id: differentiable_attr_derivative_not_function - msg: >- - registered derivative %0 must be a 'func' declaration + msg: "registered derivative %0 must be a 'func' declaration" - id: differentiable_attr_class_derivative_not_final - msg: >- - class member derivative must be final + msg: "class member derivative must be final" - id: differentiable_attr_invalid_access - msg: >- - derivative function %0 is required to either be public or - '@usableFromInline' because the original function %1 is public or - '@usableFromInline' + msg: "derivative function %0 is required to either be public or '@usableFromInline' because the original function %1 is public or '@usableFromInline'" - id: differentiable_attr_protocol_req_where_clause - msg: >- - '@differentiable' attribute on protocol requirement cannot specify - 'where' clause + msg: "'@differentiable' attribute on protocol requirement cannot specify 'where' clause" - id: differentiable_attr_class_member_dynamic_self_result_unsupported - msg: >- - '@differentiable' attribute cannot be declared on class members returning - 'Self' + msg: "'@differentiable' attribute cannot be declared on class members returning 'Self'" - id: differentiable_attr_nonfinal_class_init_unsupported - msg: >- - '@differentiable' attribute cannot be declared on 'init' in a non-final - class; consider making %0 final + msg: "'@differentiable' attribute cannot be declared on 'init' in a non-final class; consider making %0 final" - id: differentiable_attr_empty_where_clause - msg: >- - empty 'where' clause in '@differentiable' attribute + msg: "empty 'where' clause in '@differentiable' attribute" - id: differentiable_attr_where_clause_for_nongeneric_original - msg: >- - 'where' clause is valid only when original function is generic %0 + msg: "'where' clause is valid only when original function is generic %0" - id: differentiable_attr_layout_req_unsupported - msg: >- - '@differentiable' attribute does not yet support layout requirements + msg: "'@differentiable' attribute does not yet support layout requirements" - id: overriding_decl_missing_differentiable_attr - msg: >- - overriding declaration is missing attribute '%0' + msg: "overriding declaration is missing attribute '%0'" - id: protocol_witness_missing_differentiable_attr - msg: >- - candidate is missing attribute '%0' + msg: "candidate is missing attribute '%0'" - id: protocol_witness_missing_differentiable_attr_nonpublic_other_file - msg: >- - non-public %1 %2 must have explicit '%0' attribute to satisfy requirement - %3 %4 (in protocol %6) because it is declared in a different file than the - conformance of %5 to %6 + msg: "non-public %1 %2 must have explicit '%0' attribute to satisfy requirement %3 %4 (in protocol %6) because it is declared in a different file than the conformance of %5 to %6" - id: derivative_attr_expected_result_tuple - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; first element must have label 'value:' and second element - must have label 'pullback:' or 'differential:' + msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; first element must have label 'value:' and second element must have label 'pullback:' or 'differential:'" - id: derivative_attr_invalid_result_tuple_value_label - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; first element must have label 'value:' + msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; first element must have label 'value:'" - id: derivative_attr_invalid_result_tuple_func_label - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; second element must have label 'pullback:' or 'differential:' + msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; second element must have label 'pullback:' or 'differential:'" - id: derivative_attr_result_value_not_differentiable - msg: >- - '@derivative(of:)' attribute requires function to return a two-element - tuple; first element type %0 must conform to 'Differentiable' + msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; first element type %0 must conform to 'Differentiable'" - id: derivative_attr_result_func_type_mismatch - msg: >- - function result's %0 type does not match %1 + msg: "function result's %0 type does not match %1" - id: derivative_attr_result_func_type_mismatch_note - msg: >- - %0 does not have expected type %1 + msg: "%0 does not have expected type %1" - id: derivative_attr_result_func_original_note - msg: >- - %0 defined here + msg: "%0 defined here" - id: derivative_attr_not_in_same_file_as_original - msg: >- - derivative not in the same file as the original function + msg: "derivative not in the same file as the original function" - id: derivative_attr_original_stored_property_unsupported - msg: >- - cannot register derivative for stored property %0 + msg: "cannot register derivative for stored property %0" - id: derivative_attr_class_member_dynamic_self_result_unsupported - msg: >- - cannot register derivative for class member %0 returning 'Self' + msg: "cannot register derivative for class member %0 returning 'Self'" - id: derivative_attr_nonfinal_class_init_unsupported - msg: >- - cannot register derivative for 'init' in a non-final class; consider - making %0 final - + msg: "cannot register derivative for 'init' in a non-final class; consider making %0 final" + +- id: derivative_attr_unsupported_accessor_kind + msg: "cannot register derivative for %0" + - id: derivative_attr_class_setter_unsupported - msg: >- - cannot yet register derivative for class property or subscript setters + msg: "cannot yet register derivative for class property or subscript setters" + +- id: derivative_attr_protocol_requirement_unsupported + msg: "cannot yet register derivative default implementation for protocol requirements" - id: derivative_attr_original_already_has_derivative - msg: >- - a derivative already exists for %0 + msg: "a derivative already exists for %0" - id: derivative_attr_duplicate_note - msg: >- - other attribute declared here + msg: "other attribute declared here" - id: derivative_attr_access_level_mismatch - msg: >- - derivative function must have same access level as original function; - derivative function %2 is %select{private|fileprivate|internal|public|open}3, - but original function %0 is %select{private|fileprivate|internal|public|open}1 + msg: "derivative function must have same access level as original function; derivative function %2 is %select{private|fileprivate|internal|public|open}3, but original function %0 is %select{private|fileprivate|internal|public|open}1" - id: derivative_attr_fix_access - msg: >- - mark the derivative function as - '%select{private|fileprivate|internal|@usableFromInline|@usableFromInline}0' - to match the original function + msg: "mark the derivative function as '%select{private|fileprivate|internal|@usableFromInline|@usableFromInline}0' to match the original function" - id: transpose_attr_invalid_linearity_parameter_or_result - msg: >- - cannot transpose with respect to original %select{result|parameter}1 '%0' - that does not conform to 'Differentiable' and satisfy '%0 == %0.TangentVector' + msg: "cannot transpose with respect to original %select{result|parameter}1 '%0' that does not conform to 'Differentiable' and satisfy '%0 == %0.TangentVector'" - id: transpose_attr_overload_not_found - msg: >- - could not find function %0 with expected type %1 + msg: "could not find function %0 with expected type %1" - id: transpose_attr_cannot_use_named_wrt_params - msg: >- - cannot use named 'wrt' parameters in '@transpose(of:)' attribute, found %0 + msg: "cannot use named 'wrt' parameters in '@transpose(of:)' attribute, found %0" - id: transpose_attr_wrt_self_must_be_static - msg: >- - the transpose of an instance method must be a 'static' method in the same - type when 'self' is a linearity parameter + msg: "the transpose of an instance method must be a 'static' method in the same type when 'self' is a linearity parameter" - id: transpose_attr_wrt_self_self_type_mismatch_note - msg: >- - the transpose is declared in %0 but the original function is declared in %1 + msg: "the transpose is declared in %0 but the original function is declared in %1" + +- id: autodiff_attr_original_decl_ambiguous + msg: "referenced declaration %0 is ambiguous" + +- id: autodiff_attr_original_decl_ambiguous_candidate + msg: "candidate %0 found here" + +- id: autodiff_attr_original_decl_none_valid + msg: "referenced declaration %0 could not be resolved" - id: autodiff_attr_original_decl_invalid_kind - msg: >- - %0 is not a 'func', 'init', 'subscript', or 'var' computed property - declaration + msg: "candidate %0 is not a 'func', 'init', 'subscript', or 'var' computed property declaration" + +- id: autodiff_attr_original_decl_missing_accessor + msg: "candidate %0 does not have a %1" + +- id: autodiff_attr_original_decl_type_mismatch + msg: "candidate %0 does not have %select{expected type|type equal to or less constrained than}2 %1" - id: autodiff_attr_original_decl_not_same_type_context - msg: >- - %0 is not defined in the current type context + msg: "candidate %0 is not defined in the current type context" - id: autodiff_attr_original_void_result - msg: >- - cannot differentiate void function %0 + msg: "cannot differentiate void function %0" - id: autodiff_attr_original_multiple_semantic_results - msg: >- - cannot differentiate functions with both an 'inout' parameter and a result + msg: "cannot differentiate functions with both an 'inout' parameter and a result" - id: autodiff_attr_result_not_differentiable - msg: >- - can only differentiate functions with results that conform to - 'Differentiable', but %0 does not conform to 'Differentiable' + msg: "can only differentiate functions with results that conform to 'Differentiable', but %0 does not conform to 'Differentiable'" + +- id: autodiff_attr_opaque_result_type_unsupported + msg: "cannot differentiate functions returning opaque result types" - id: diff_function_no_parameters - msg: >- - %0 has no parameters to differentiate with respect to + msg: "%0 has no parameters to differentiate with respect to" - id: diff_params_clause_param_name_unknown - msg: >- - unknown parameter name %0 + msg: "unknown parameter name %0" - id: diff_params_clause_self_instance_method_only - msg: >- - 'self' parameter is only applicable to instance methods + msg: "'self' parameter is only applicable to instance methods" - id: diff_params_clause_self_must_be_first - msg: >- - 'self' parameter must come first in the parameter list + msg: "'self' parameter must come first in the parameter list" - id: diff_params_clause_params_not_original_order - msg: >- - parameters must be specified in original order + msg: "parameters must be specified in original order" - id: diff_params_clause_param_index_out_of_range - msg: >- - parameter index is larger than total number of parameters + msg: "parameter index is larger than total number of parameters" - id: diff_params_clause_no_inferred_parameters - msg: >- - no differentiation parameters could be inferred; must differentiate with - respect to at least one parameter conforming to 'Differentiable' + msg: "no differentiation parameters could be inferred; must differentiate with respect to at least one parameter conforming to 'Differentiable'" - id: diff_params_clause_cannot_diff_wrt_inout_parameter - msg: >- - cannot differentiate with respect to 'inout' parameter (%0) + msg: "cannot differentiate with respect to 'inout' parameter (%0)" - id: diff_params_clause_param_not_differentiable - msg: >- - can only differentiate with respect to parameters that conform to - 'Differentiable', but %0 does not conform to 'Differentiable' + msg: "can only differentiate with respect to parameters that conform to 'Differentiable', but %0 does not conform to 'Differentiable'" - id: found_candidate - msg: >- - found this candidate + msg: "found this candidate" - id: found_candidate_type - msg: >- - found candidate with type %0 + msg: "found candidate with type %0" - id: no_MaxBuiltinFloatType_found - msg: >- - standard library error: _MaxBuiltinFloatType is not properly defined + msg: "standard library error: _MaxBuiltinFloatType is not properly defined" - id: no_member_of_module - msg: >- - module %0 has no member named %1 + msg: "module %0 has no member named %1" - id: super_with_no_base_class - msg: >- - 'super' members cannot be referenced in a root class + msg: "'super' members cannot be referenced in a root class" - id: bad_init_ref_base - msg: >- - 'init' can only refer to the initializers of 'self'%select{| or 'super'}0 + msg: "'init' can only refer to the initializers of 'self'%select{| or 'super'}0" - id: init_delegation_outside_initializer - msg: >- - initializer delegation can only occur within an initializer + msg: "initializer delegation can only occur within an initializer" - id: init_delegates_and_chains - msg: >- - initializer cannot both delegate ('self.init') and chain to a superclass - initializer ('super.init') + msg: "initializer cannot both delegate ('self.init') and chain to a superclass initializer ('super.init')" - id: init_delegation_or_chain - msg: >- - previous %select{delegation|chaining}0 call is here + msg: "previous %select{delegation|chaining}0 call is here" - id: delegating_convenience_super_init - msg: >- - convenience initializer for %0 must delegate (with 'self.init') rather - than chaining to a superclass initializer (with 'super.init') + msg: "convenience initializer for %0 must delegate (with 'self.init') rather than chaining to a superclass initializer (with 'super.init')" - id: delegating_designated_init - msg: >- - designated initializer for %0 cannot delegate (with 'self.init'); did you - mean this to be a convenience initializer? + msg: "designated initializer for %0 cannot delegate (with 'self.init'); did you mean this to be a convenience initializer?" - id: delegating_designated_init_in_extension - msg: >- - designated initializer for %0 cannot delegate (with 'self.init') + msg: "designated initializer for %0 cannot delegate (with 'self.init')" - id: delegation_here - msg: >- - delegation occurs here + msg: "delegation occurs here" - id: chain_convenience_init - msg: >- - must call a designated initializer of the superclass %0 + msg: "must call a designated initializer of the superclass %0" - id: delegate_chain_nonoptional_to_optional - msg: >- - a non-failable initializer cannot %select{delegate|chain}0 to failable - initializer %1 written with 'init?' + msg: "a non-failable initializer cannot %select{delegate|chain}0 to failable initializer %1 written with 'init?'" - id: init_force_unwrap - msg: >- - force potentially-failing result with '!' + msg: "force potentially-failing result with '!'" - id: init_propagate_failure - msg: >- - propagate the failure with 'init?' + msg: "propagate the failure with 'init?'" - id: delegate_chain_nonoptional_to_optional_try - msg: >- - a non-failable initializer cannot use 'try?' to %select{delegate|chain}0 - to another initializer + msg: "a non-failable initializer cannot use 'try?' to %select{delegate|chain}0 to another initializer" - id: init_delegate_force_try - msg: >- - force potentially-failing result with 'try!' + msg: "force potentially-failing result with 'try!'" - id: init_delegation_nested - msg: >- - %select{initializer delegation ('self.init')|initializer chaining - ('super.init')}0 cannot be nested in another %select{expression|statement}1 + msg: "%select{initializer delegation ('self.init')|initializer chaining ('super.init')}0 cannot be nested in another %select{expression|statement}1" - id: convenience_init_here - msg: >- - convenience initializer is declared here + msg: "convenience initializer is declared here" - id: designated_init_in_extension - msg: >- - designated initializer cannot be declared in an extension of %0; did you - mean this to be a convenience initializer? + msg: "designated initializer cannot be declared in an extension of %0; did you mean this to be a convenience initializer?" - id: cfclass_designated_init_in_extension - msg: >- - designated initializer cannot be declared in an extension of %0 + msg: "designated initializer cannot be declared in an extension of %0" - id: enumstruct_convenience_init - msg: >- - delegating initializers in %0 are not marked with 'convenience' + msg: "delegating initializers in %0 are not marked with 'convenience'" - id: nonclass_convenience_init - msg: >- - convenience initializer not allowed in non-class type %0 + msg: "convenience initializer not allowed in non-class type %0" - id: cfclass_convenience_init - msg: >- - convenience initializers are not supported in extensions of CF types + msg: "convenience initializers are not supported in extensions of CF types" - id: dynamic_construct_class - msg: >- - constructing an object of class type %0 with a metatype value must use a - 'required' initializer + msg: "constructing an object of class type %0 with a metatype value must use a 'required' initializer" - id: note_nonrequired_initializer - msg: >- - selected %select{non-required|implicit}0 initializer %1 + msg: "selected %select{non-required|implicit}0 initializer %1" - id: construct_protocol_value - msg: >- - value of type %0 is a protocol; it cannot be instantiated + msg: "value of type %0 is a protocol; it cannot be instantiated" - id: construct_protocol_by_name - msg: >- - protocol type %0 cannot be instantiated + msg: "protocol type %0 cannot be instantiated" - id: unknown_binop - msg: >- - operator is not a known binary operator + msg: "operator is not a known binary operator" - id: non_associative_adjacent_operators - msg: >- - adjacent operators are in non-associative precedence group %0 + msg: "adjacent operators are in non-associative precedence group %0" - id: unordered_adjacent_operators - msg: >- - adjacent operators are in unordered precedence groups %0 and %1 + msg: "adjacent operators are in unordered precedence groups %0 and %1" - id: missing_builtin_precedence_group - msg: >- - broken standard library: missing builtin precedence group %0 + msg: "broken standard library: missing builtin precedence group %0" - id: try_rhs - msg: >- - '%select{try|try!|try?}0' cannot appear to the right of a non-assignment - operator + msg: "'%select{try|try!|try?|await}0' cannot appear to the right of a non-assignment operator" - id: try_if_rhs_noncovering - msg: >- - '%select{try|try!|try?}0' following conditional operator does not cover - everything to its right + msg: "'%select{try|try!|try?|await}0' following conditional operator does not cover everything to its right" - id: try_assign_rhs_noncovering - msg: >- - '%select{try|try!|try?}0' following assignment operator does not cover - everything to its right + msg: "'%select{try|try!|try?|await}0' following assignment operator does not cover everything to its right" - id: broken_bool - msg: >- - type 'Bool' is broken + msg: "type 'Bool' is broken" - id: inject_forced_downcast - msg: >- - treating a forced downcast to %0 as optional will never produce 'nil' + msg: "treating a forced downcast to %0 as optional will never produce 'nil'" - id: forced_to_conditional_downcast - msg: >- - use 'as?' to perform a conditional downcast to %0 + msg: "use 'as?' to perform a conditional downcast to %0" - id: silence_inject_forced_downcast - msg: >- - add parentheses around the cast to silence this warning + msg: "add parentheses around the cast to silence this warning" - id: conditional_downcast_foreign - msg: >- - conditional downcast to CoreFoundation type %0 will always succeed + msg: "conditional downcast to CoreFoundation type %0 will always succeed" - id: note_explicitly_compare_cftypeid - msg: >- - did you mean to explicitly compare the CFTypeIDs of %0 and %1? + msg: "did you mean to explicitly compare the CFTypeIDs of %0 and %1?" - id: optional_used_as_boolean - msg: >- - optional type %0 cannot be used as a boolean; test for '%select{!|=}1= - nil' instead + msg: "optional type %0 cannot be used as a boolean; test for '%select{!|=}1= nil' instead" - id: integer_used_as_boolean - msg: >- - type %0 cannot be used as a boolean; test for '%select{!|=}1= 0' instead + msg: "type %0 cannot be used as a boolean; test for '%select{!|=}1= 0' instead" - id: interpolation_missing_proto - msg: >- - string interpolation requires the protocol - 'ExpressibleByStringInterpolation' to be defined + msg: "string interpolation requires the protocol 'ExpressibleByStringInterpolation' to be defined" - id: interpolation_broken_proto - msg: >- - protocol 'ExpressibleByStringInterpolation' is broken + msg: "protocol 'ExpressibleByStringInterpolation' is broken" - id: object_literal_broken_proto - msg: >- - object literal protocol is broken + msg: "object literal protocol is broken" - id: discard_expr_outside_of_assignment - msg: >- - '_' can only appear in a pattern or on the left side of an assignment + msg: "'_' can only appear in a pattern or on the left side of an assignment" - id: discard_expr_void_result_redundant - msg: >- - using '_' to ignore the result of a Void-returning function is redundant + msg: "using '_' to ignore the result of a Void-returning function is redundant" - id: collection_literal_heterogeneous - msg: >- - heterogeneous collection literal could only be inferred to %0; add - explicit type annotation if this is intentional + msg: "heterogeneous collection literal could only be inferred to %0; add explicit type annotation if this is intentional" - id: collection_literal_empty - msg: >- - empty collection literal requires an explicit type + msg: "empty collection literal requires an explicit type" - id: unresolved_member_no_inference - msg: >- - reference to member %0 cannot be resolved without a contextual type + msg: "reference to member %0 cannot be resolved without a contextual type" - id: cannot_infer_base_of_unresolved_member - msg: >- - cannot infer contextual base in reference to member %0 + msg: "cannot infer contextual base in reference to member %0" - id: unresolved_nil_literal - msg: >- - 'nil' requires a contextual type + msg: "'nil' requires a contextual type" - id: cannot_force_unwrap_nil_literal - msg: >- - 'nil' literal cannot be force unwrapped + msg: "'nil' literal cannot be force unwrapped" - id: type_of_expression_is_ambiguous - msg: >- - type of expression is ambiguous without more context + msg: "type of expression is ambiguous without more context" - id: failed_to_produce_diagnostic - msg: >- - failed to produce diagnostic for expression; please file a bug report + msg: "failed to produce diagnostic for expression; please file a bug report" - id: missing_protocol - msg: >- - missing protocol %0 + msg: "missing protocol %0" - id: nil_literal_broken_proto - msg: >- - protocol 'ExpressibleByNilLiteral' is broken + msg: "protocol 'ExpressibleByNilLiteral' is broken" - id: builtin_integer_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinIntegerLiteral' is broken + msg: "protocol '_ExpressibleByBuiltinIntegerLiteral' is broken" - id: integer_literal_broken_proto - msg: >- - protocol 'ExpressibleByIntegerLiteral' is broken + msg: "protocol 'ExpressibleByIntegerLiteral' is broken" - id: builtin_float_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinFloatLiteral' is broken + msg: "protocol '_ExpressibleByBuiltinFloatLiteral' is broken" - id: float_literal_broken_proto - msg: >- - protocol 'ExpressibleByFloatLiteral' is broken + msg: "protocol 'ExpressibleByFloatLiteral' is broken" - id: builtin_boolean_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinBooleanLiteral' is broken + msg: "protocol '_ExpressibleByBuiltinBooleanLiteral' is broken" - id: boolean_literal_broken_proto - msg: >- - protocol 'ExpressibleByBooleanLiteral' is broken + msg: "protocol 'ExpressibleByBooleanLiteral' is broken" - id: builtin_unicode_scalar_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinUnicodeScalarLiteral' is broken + msg: "protocol '_ExpressibleByBuiltinUnicodeScalarLiteral' is broken" - id: unicode_scalar_literal_broken_proto - msg: >- - protocol 'ExpressibleByUnicodeScalarLiteral' is broken + msg: "protocol 'ExpressibleByUnicodeScalarLiteral' is broken" - id: builtin_extended_grapheme_cluster_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinExtendedGraphemeClusterLiteral' is broken + msg: "protocol '_ExpressibleByBuiltinExtendedGraphemeClusterLiteral' is broken" - id: extended_grapheme_cluster_literal_broken_proto - msg: >- - protocol 'ExpressibleByExtendedGraphemeClusterLiteral' is broken + msg: "protocol 'ExpressibleByExtendedGraphemeClusterLiteral' is broken" - id: builtin_string_literal_broken_proto - msg: >- - protocol '_ExpressibleByBuiltinStringLiteral' is broken + msg: "protocol '_ExpressibleByBuiltinStringLiteral' is broken" - id: string_literal_broken_proto - msg: >- - protocol 'ExpressibleByStringLiteral' is broken + msg: "protocol 'ExpressibleByStringLiteral' is broken" - id: should_use_dictionary_literal - msg: >- - dictionary of type %0 cannot be %select{used|initialized}1 with array - literal + msg: "dictionary of type %0 cannot be %select{used|initialized}1 with array literal" - id: meant_dictionary_lit - msg: >- - did you mean to use a dictionary literal instead? + msg: "did you mean to use a dictionary literal instead?" - id: should_use_empty_dictionary_literal - msg: >- - use [:] to get an empty dictionary literal + msg: "use [:] to get an empty dictionary literal" - id: type_is_not_dictionary - msg: >- - contextual type %0 cannot be used with dictionary literal + msg: "contextual type %0 cannot be used with dictionary literal" - id: cannot_explicitly_specialize_generic_function - msg: >- - cannot explicitly specialize a generic function + msg: "cannot explicitly specialize a generic function" - id: not_a_generic_definition - msg: >- - cannot specialize a non-generic definition + msg: "cannot specialize a non-generic definition" - id: not_a_generic_type - msg: >- - cannot specialize non-generic type %0 + msg: "cannot specialize non-generic type %0" - id: type_parameter_count_mismatch - msg: >- - generic type %0 specialized with %select{too many|too few}3 type - parameters (got %2, but expected %1) + msg: "generic type %0 specialized with %select{too many|too few}3 type parameters (got %2, but expected %1)" - id: generic_type_requires_arguments - msg: >- - reference to generic type %0 requires arguments in <...> + msg: "reference to generic type %0 requires arguments in <...>" - id: descriptive_generic_type_declared_here - msg: >- - %0 declared here + msg: "%0 declared here" - id: use_of_void_pointer - msg: >- - Unsafe%0Pointer has been replaced by Unsafe%0RawPointer + msg: "Unsafe%0Pointer has been replaced by Unsafe%0RawPointer" - id: ambiguous_decl_ref - msg: >- - ambiguous use of %0 + msg: "ambiguous use of %0" - id: ambiguous_operator_ref - msg: >- - ambiguous use of operator %0 + msg: "ambiguous use of operator %0" - id: ambiguous_because_of_trailing_closure - msg: >- - %select{use an explicit argument label instead of a trailing - closure|avoid using a trailing closure}0 to call %1 + msg: "%select{use an explicit argument label instead of a trailing closure|avoid using a trailing closure}0 to call %1" - id: partial_application_of_function_invalid - msg: >- - partial application of %select{'mutating' method|'super.init' initializer - chain|'self.init' initializer delegation|'super' instance method with - metatype base}0 is not allowed + msg: "partial application of %select{'mutating' method|'super.init' initializer chain|'self.init' initializer delegation|'super' instance method with metatype base}0 is not allowed" - id: partial_application_of_function_invalid_swift4 - msg: >- - partial application of %select{'mutating' method|'super.init' initializer - chain|'self.init' initializer delegation|'super' instance method with - metatype base}0 is not allowed; calling the function has undefined - behavior and will be an error in future Swift versions + msg: "partial application of %select{'mutating' method|'super.init' initializer chain|'self.init' initializer delegation|'super' instance method with metatype base}0 is not allowed; calling the function has undefined behavior and will be an error in future Swift versions" - id: self_assignment_var - msg: >- - assigning a variable to itself + msg: "assigning a variable to itself" - id: self_assignment_prop - msg: >- - assigning a property to itself + msg: "assigning a property to itself" - id: property_use_in_closure_without_explicit_self - msg: >- - reference to property %0 in closure requires explicit use of 'self' to - make capture semantics explicit + msg: "reference to property %0 in closure requires explicit use of 'self' to make capture semantics explicit" - id: method_call_in_closure_without_explicit_self - msg: >- - call to method %0 in closure requires explicit use of 'self' to make - capture semantics explicit + msg: "call to method %0 in closure requires explicit use of 'self' to make capture semantics explicit" - id: note_capture_self_explicitly - msg: >- - capture 'self' explicitly to enable implicit 'self' in this closure + msg: "capture 'self' explicitly to enable implicit 'self' in this closure" - id: note_reference_self_explicitly - msg: >- - reference 'self.' explicitly + msg: "reference 'self.' explicitly" - id: note_other_self_capture - msg: >- - variable other than 'self' captured here under the name 'self' does not - enable implicit 'self' + msg: "variable other than 'self' captured here under the name 'self' does not enable implicit 'self'" - id: note_self_captured_weakly - msg: >- - weak capture of 'self' here does not enable implicit 'self' + msg: "weak capture of 'self' here does not enable implicit 'self'" - id: implicit_use_of_self_in_closure - msg: >- - implicit use of 'self' in closure; use 'self.' to make capture semantics - explicit + msg: "implicit use of 'self' in closure; use 'self.' to make capture semantics explicit" - id: recursive_accessor_reference - msg: >- - attempting to %select{access|modify}1 %0 within its own - %select{getter|setter}1 + msg: "attempting to %select{access|modify}1 %0 within its own %select{getter|setter}1" - id: recursive_accessor_reference_silence - msg: >- - access 'self' explicitly to silence this warning + msg: "access 'self' explicitly to silence this warning" - id: store_in_willset - msg: >- - attempting to store to property %0 within its own willSet, which is about - to be overwritten by the new value + msg: "attempting to store to property %0 within its own willSet, which is about to be overwritten by the new value" - id: value_of_module_type - msg: >- - expected module member name after module name + msg: "expected module member name after module name" - id: value_of_metatype_type - msg: >- - expected member name or constructor call after type name + msg: "expected member name or constructor call after type name" - id: add_parens_to_type - msg: >- - add arguments after the type to construct a value of the type + msg: "add arguments after the type to construct a value of the type" - id: add_self_to_type - msg: >- - use '.self' to reference the type object + msg: "use '.self' to reference the type object" - id: warn_unqualified_access - msg: >- - use of %0 treated as a reference to %1 in %2 %3 + msg: "use of %0 treated as a reference to %1 in %2 %3" - id: fix_unqualified_access_member - msg: >- - use 'self.' to silence this warning + msg: "use 'self.' to silence this warning" - id: fix_unqualified_access_top_level - msg: >- - use '%0' to reference the %1 + msg: "use '%0' to reference the %1" - id: fix_unqualified_access_top_level_multi - msg: >- - use '%0' to reference the %1 in module %2 + msg: "use '%0' to reference the %1 in module %2" - id: warn_deprecated_conditional_conformance_outer_access - msg: >- - use of %0 as reference to %1 in %2 %3 will change in future versions of - Swift to reference %4 in %5 %6 which comes via a conditional conformance + msg: "use of %0 as reference to %1 in %2 %3 will change in future versions of Swift to reference %4 in %5 %6 which comes via a conditional conformance" - id: fix_deprecated_conditional_conformance_outer_access - msg: >- - use '%0' to continue to reference the %1 + msg: "use '%0' to continue to reference the %1" - id: unsupported_special_decl_ref - msg: >- - referencing %0 as a function value is not implemented + msg: "referencing %0 as a function value is not implemented" - id: bitcasting_away_noescape - msg: >- - 'unsafeBitCast' from non-escaping function type %0 to escaping function - type %1 is undefined; use 'withoutActuallyEscaping' to temporarily escape a - function + msg: "'unsafeBitCast' from non-escaping function type %0 to escaping function type %1 is undefined; use 'withoutActuallyEscaping' to temporarily escape a function" - id: bitcasting_to_change_function_rep - msg: >- - 'unsafeBitCast' from function type %0 to %1 changes @convention and is - undefined; use an implicit conversion to change conventions + msg: "'unsafeBitCast' from function type %0 to %1 changes @convention and is undefined; use an implicit conversion to change conventions" - id: bitcasting_to_downcast - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with 'unsafeDowncast' + msg: "'unsafeBitCast' from %0 to %1 can be replaced with 'unsafeDowncast'" - id: bitcasting_is_no_op - msg: >- - 'unsafeBitCast' from %0 to %1 is unnecessary and can be removed + msg: "'unsafeBitCast' from %0 to %1 is unnecessary and can be removed" - id: bitcasting_to_change_pointer_kind - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with %2 initializer + msg: "'unsafeBitCast' from %0 to %1 can be replaced with %2 initializer" - id: bitcasting_to_change_pointee_type - msg: >- - 'unsafeBitCast' from %0 to %1 changes pointee type and may lead to - undefined behavior; use the 'withMemoryRebound' method on %0 - to rebind the type of memory + msg: "'unsafeBitCast' from %0 to %1 changes pointee type and may lead to undefined behavior; use the 'withMemoryRebound' method on %0 to rebind the type of memory" - id: bitcasting_to_give_type_to_raw_pointer - msg: >- - 'unsafeBitCast' from %0 to %1 gives a type to a raw pointer and may lead - to undefined behavior + msg: "'unsafeBitCast' from %0 to %1 gives a type to a raw pointer and may lead to undefined behavior" - id: bitcast_assume_memory_rebound - msg: >- - use the 'assumingMemoryBound' method if the pointer is known to point to - an existing value or array of type %0 in memory + msg: "use the 'assumingMemoryBound' method if the pointer is known to point to an existing value or array of type %0 in memory" - id: bitcast_bind_memory - msg: >- - use the 'bindMemory' method to assign type %0 to uninitialized raw memory + msg: "use the 'bindMemory' method to assign type %0 to uninitialized raw memory" - id: bitcasting_for_number_bit_pattern_init - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern:' - initializer on %1 + msg: "'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern:' initializer on %1" - id: bitcasting_for_number_bit_pattern_property - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern' property - on %0 + msg: "'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern' property on %0" - id: bitcasting_to_change_from_unsized_to_sized_int - msg: >- - 'unsafeBitCast' from %0 to %1 can be replaced with %1 initializer + msg: "'unsafeBitCast' from %0 to %1 can be replaced with %1 initializer" - id: use_of_qq_on_non_optional_value - msg: >- - left side of nil coalescing operator '??' has non-optional type %0, so - the right side is never used + msg: "left side of nil coalescing operator '??' has non-optional type %0, so the right side is never used" - id: nonoptional_compare_to_nil - msg: >- - comparing non-optional value of type %0 to 'nil' always returns - %select{false|true}1 + msg: "comparing non-optional value of type %0 to 'nil' always returns %select{false|true}1" - id: optional_check_nonoptional - msg: >- - non-optional expression of type %0 used in a check for optionals + msg: "non-optional expression of type %0 used in a check for optionals" - id: optional_check_promotion - msg: >- - explicitly specified type %0 adds an additional level of optional to the - initializer, making the optional check always succeed + msg: "explicitly specified type %0 adds an additional level of optional to the initializer, making the optional check always succeed" - id: optional_pattern_match_promotion - msg: >- - pattern match introduces an implicit promotion from %0 to %1 + msg: "pattern match introduces an implicit promotion from %0 to %1" - id: optional_to_any_coercion - msg: >- - expression implicitly coerced from %0 to %1 + msg: "expression implicitly coerced from %0 to %1" - id: iuo_to_any_coercion - msg: >- - coercion of implicitly unwrappable value of type %0 to %1 does not unwrap - optional + msg: "coercion of implicitly unwrappable value of type %0 to %1 does not unwrap optional" - id: iuo_to_any_coercion_note - msg: >- - implicitly unwrapped %0 %1 declared here + msg: "implicitly unwrapped %0 %1 declared here" - id: iuo_to_any_coercion_note_func_result - msg: >- - %0 %1 with implicitly unwrapped result type is declared here + msg: "%0 %1 with implicitly unwrapped result type is declared here" - id: default_optional_to_any - msg: >- - provide a default value to avoid this warning + msg: "provide a default value to avoid this warning" - id: force_optional_to_any - msg: >- - force-unwrap the value to avoid this warning + msg: "force-unwrap the value to avoid this warning" - id: silence_optional_to_any - msg: >- - explicitly cast to %0 with '%1' to silence this warning + msg: "explicitly cast to %0 with '%1' to silence this warning" - id: debug_description_in_string_interpolation_segment - msg: >- - string interpolation produces a debug description for %select{an - optional|a function}0 value; did you mean to make this explicit? + msg: "string interpolation produces a debug description for %select{an optional|a function}0 value; did you mean to make this explicit?" - id: silence_debug_description_in_interpolation_segment_call - msg: >- - use 'String(describing:)' to silence this warning + msg: "use 'String(describing:)' to silence this warning" - id: noescape_parameter - msg: >- - parameter %0 is implicitly non-escaping + msg: "parameter %0 is implicitly non-escaping" - id: generic_parameters_always_escaping - msg: >- - generic parameters are always considered '@escaping' + msg: "generic parameters are always considered '@escaping'" - id: passing_noescape_to_escaping - msg: >- - passing non-escaping parameter %0 to function expecting an @escaping closure + msg: "passing non-escaping parameter %0 to function expecting an @escaping closure" - id: converting_noespace_param_to_generic_type - msg: >- - converting non-escaping parameter %0 to generic parameter %1 may allow it - to escape + msg: "converting non-escaping parameter %0 to generic parameter %1 may allow it to escape" - id: assigning_noescape_to_escaping - msg: >- - assigning non-escaping parameter %0 to an @escaping closure + msg: "assigning non-escaping parameter %0 to an @escaping closure" - id: general_noescape_to_escaping - msg: >- - using non-escaping parameter %0 in a context expecting an @escaping closure + msg: "using non-escaping parameter %0 in a context expecting an @escaping closure" - id: converting_noescape_to_type - msg: >- - converting non-escaping value to %0 may allow it to escape + msg: "converting non-escaping value to %0 may allow it to escape" - id: capture_across_type_decl - msg: >- - %0 declaration cannot close over value %1 defined in outer scope + msg: "%0 declaration cannot close over value %1 defined in outer scope" - id: jump_out_of_defer - msg: >- - '%0' cannot transfer control out of a defer statement + msg: "'%0' cannot transfer control out of a defer statement" - id: defer_stmt_at_block_end - msg: >- - 'defer' statement at end of scope always executes immediately; replace - with 'do' statement to silence this warning + msg: "'defer' statement at end of scope always executes immediately; replace with 'do' statement to silence this warning" - id: return_invalid_outside_func - msg: >- - return invalid outside of a func + msg: "return invalid outside of a func" - id: return_expr_missing - msg: >- - non-void function should return a value + msg: "non-void function should return a value" - id: return_non_failable_init - msg: >- - only a failable initializer can return 'nil' + msg: "only a failable initializer can return 'nil'" - id: make_init_failable - msg: >- - use 'init?' to make the initializer %0 failable + msg: "use 'init?' to make the initializer %0 failable" - id: return_init_non_nil - msg: >- - 'nil' is the only return value permitted in an initializer + msg: "'nil' is the only return value permitted in an initializer" - id: if_always_true - msg: >- - 'if' condition is always true + msg: "'if' condition is always true" - id: while_always_true - msg: >- - 'while' condition is always true + msg: "'while' condition is always true" - id: guard_always_succeeds - msg: >- - 'guard' condition is always true, body is unreachable + msg: "'guard' condition is always true, body is unreachable" - id: expression_unused_closure - msg: >- - closure expression is unused + msg: "closure expression is unused" - id: expression_unused_function - msg: >- - expression resolves to an unused function + msg: "expression resolves to an unused function" - id: expression_unused_lvalue - msg: >- - expression resolves to an unused %select{variable|property|subscript}0 + msg: "expression resolves to an unused %select{variable|property|subscript}0" - id: expression_unused_result_call - msg: >- - result of call to %0 is unused + msg: "result of call to %0 is unused" - id: expression_unused_result_operator - msg: >- - result of operator %0 is unused + msg: "result of operator %0 is unused" - id: expression_unused_result_unknown - msg: >- - result of call to %select{function|closure}0 returning %1 is unused + msg: "result of call to %select{function|closure}0 returning %1 is unused" - id: expression_unused_result - msg: >- - expression of type %0 is unused + msg: "expression of type %0 is unused" - id: expression_unused_init_result - msg: >- - result of %0 initializer is unused + msg: "result of %0 initializer is unused" - id: expression_unused_optional_try - msg: >- - result of 'try?' is unused + msg: "result of 'try?' is unused" - id: expression_unused_selector_result - msg: >- - result of '#selector' is unused + msg: "result of '#selector' is unused" - id: expression_unused_literal - msg: >- - %0 literal is unused + msg: "%0 literal is unused" - id: assignment_lhs_not_lvalue - msg: >- - cannot assign to immutable expression of type %0 + msg: "cannot assign to immutable expression of type %0" - id: assignment_lhs_is_apply_expression - msg: >- - expression is not assignable: %0 + msg: "expression is not assignable: %0" - id: assignment_lhs_is_immutable_variable - msg: >- - cannot assign to value: %0 + msg: "cannot assign to value: %0" - id: assignment_lhs_is_immutable_property - msg: >- - cannot assign to property: %0 + msg: "cannot assign to property: %0" - id: assignment_subscript_has_immutable_base - msg: >- - cannot assign through subscript: %0 + msg: "cannot assign through subscript: %0" - id: assignment_dynamic_property_has_immutable_base - msg: >- - cannot assign through dynamic lookup property: %0 + msg: "cannot assign through dynamic lookup property: %0" - id: assignment_bang_has_immutable_subcomponent - msg: >- - cannot assign through '!': %0 + msg: "cannot assign through '!': %0" - id: candidate_is_not_assignable - msg: >- - candidate is not assignable: %0 %1 + msg: "candidate is not assignable: %0 %1" - id: change_to_mutating - msg: >- - mark %select{method|accessor}0 'mutating' to make 'self' mutable + msg: "mark %select{method|accessor}0 'mutating' to make 'self' mutable" - id: masked_mutable_property - msg: >- - add explicit '%0' to refer to mutable %1 of %2 + msg: "add explicit '%0' to refer to mutable %1 of %2" - id: assignment_let_property_delegating_init - msg: >- - 'let' property %0 may not be initialized directly; use "self.init(...)" - or "self = ..." instead + msg: "'let' property %0 may not be initialized directly; use \"self.init(...)\" or \"self = ...\" instead" - id: label_shadowed - msg: >- - label %0 cannot be reused on an inner statement + msg: "label %0 cannot be reused on an inner statement" - id: break_outside_loop - msg: >- - 'break' is only allowed inside a loop, if, do, or switch + msg: "'break' is only allowed inside a loop, if, do, or switch" - id: unlabeled_break_outside_loop - msg: >- - unlabeled 'break' is only allowed inside a loop or switch, a labeled - break is required to exit an if or do + msg: "unlabeled 'break' is only allowed inside a loop or switch, a labeled break is required to exit an if or do" - id: continue_outside_loop - msg: >- - 'continue' is only allowed inside a loop + msg: "'continue' is only allowed inside a loop" - id: continue_not_in_this_stmt - msg: >- - 'continue' cannot be used with %0 statements + msg: "'continue' cannot be used with %0 statements" - id: unresolved_label - msg: >- - cannot find label %0 in scope + msg: "cannot find label %0 in scope" - id: unresolved_label_corrected - msg: >- - cannot find label %0 in scope; did you mean %1? + msg: "cannot find label %0 in scope; did you mean %1?" - id: foreach_sequence_does_not_conform_to_expected_protocol - msg: >- - for-in loop requires %0 to conform to %1%select{|; did you mean to unwrap - optional?}2 + msg: "for-in loop requires %0 to conform to %1%select{|; did you mean to unwrap optional?}2" - id: no_match_operator - msg: >- - no binary '~=' operator available for 'switch' statement + msg: "no binary '~=' operator available for 'switch' statement" - id: fallthrough_outside_switch - msg: >- - 'fallthrough' is only allowed inside a switch + msg: "'fallthrough' is only allowed inside a switch" - id: fallthrough_from_last_case - msg: >- - 'fallthrough' without a following 'case' or 'default' block + msg: "'fallthrough' without a following 'case' or 'default' block" - id: fallthrough_into_case_with_var_binding - msg: >- - 'fallthrough' from a case which doesn't bind variable %0 + msg: "'fallthrough' from a case which doesn't bind variable %0" - id: unnecessary_cast_over_optionset - msg: >- - unnecessary cast over raw value of %0 + msg: "unnecessary cast over raw value of %0" - id: mutability_mismatch_multiple_pattern_list - msg: >- - '%select{var|let}0' pattern binding must match previous - '%select{var|let}1' pattern binding + msg: "'%select{var|let}0' pattern binding must match previous '%select{var|let}1' pattern binding" - id: type_mismatch_multiple_pattern_list - msg: >- - pattern variable bound to type %0, expected type %1 + msg: "pattern variable bound to type %0, expected type %1" - id: type_mismatch_fallthrough_pattern_list - msg: >- - pattern variable bound to type %0, fallthrough case bound to type %1 + msg: "pattern variable bound to type %0, fallthrough case bound to type %1" - id: unknown_case_must_be_catchall - msg: >- - '@unknown' is only supported for catch-all cases ("case _") + msg: "'@unknown' is only supported for catch-all cases (\"case _\")" - id: unknown_case_where_clause - msg: >- - 'where' cannot be used with '@unknown' + msg: "'where' cannot be used with '@unknown'" - id: unknown_case_multiple_patterns - msg: >- - '@unknown' cannot be applied to multiple patterns + msg: "'@unknown' cannot be applied to multiple patterns" - id: unknown_case_must_be_last - msg: >- - '@unknown' can only be applied to the last case in a switch + msg: "'@unknown' can only be applied to the last case in a switch" - id: where_on_one_item - msg: >- - 'where' only applies to the second pattern match in this case + msg: "'where' only applies to the second pattern match in this case" - id: add_where_newline - msg: >- - disambiguate by adding a line break between them if this is desired + msg: "disambiguate by adding a line break between them if this is desired" - id: duplicate_where - msg: >- - duplicate the 'where' on both patterns to check both patterns + msg: "duplicate the 'where' on both patterns to check both patterns" - id: trailing_closure_requires_parens - msg: >- - trailing closure in this context is confusable with the body of the - statement; pass as a parenthesized argument to silence this warning + msg: "trailing closure in this context is confusable with the body of the statement; pass as a parenthesized argument to silence this warning" - id: opaque_type_var_no_init - msg: >- - property declares an opaque return type, but has no initializer - expression from which to infer an underlying type + msg: "property declares an opaque return type, but has no initializer expression from which to infer an underlying type" - id: opaque_type_no_underlying_type_candidates - msg: >- - function declares an opaque return type, but has no return statements in - its body from which to infer an underlying type + msg: "function declares an opaque return type, but has no return statements in its body from which to infer an underlying type" - id: opaque_type_mismatched_underlying_type_candidates - msg: >- - function declares an opaque return type, but the return statements in its - body do not have matching underlying types + msg: "function declares an opaque return type, but the return statements in its body do not have matching underlying types" - id: opaque_type_underlying_type_candidate_here - msg: >- - return statement has underlying type %0 + msg: "return statement has underlying type %0" - id: opaque_type_self_referential_underlying_type - msg: >- - function opaque return type was inferred as %0, which defines the opaque - type in terms of itself + msg: "function opaque return type was inferred as %0, which defines the opaque type in terms of itself" - id: opaque_type_var_no_underlying_type - msg: >- - property declares an opaque return type, but cannot infer the underlying - type from its initializer expression + msg: "property declares an opaque return type, but cannot infer the underlying type from its initializer expression" - id: cannot_infer_type_for_pattern - msg: >- - type annotation missing in pattern + msg: "type annotation missing in pattern" - id: refutable_pattern_requires_initializer - msg: >- - pattern matching requires an initializer value to match against + msg: "pattern matching requires an initializer value to match against" - id: var_pattern_didnt_bind_variables - msg: >- - '%0' pattern has no effect; sub-pattern didn't bind any variables + msg: "'%0' pattern has no effect; sub-pattern didn't bind any variables" - id: iflet_pattern_matching - msg: >- - pattern matching in a condition requires the 'case' keyword + msg: "pattern matching in a condition requires the 'case' keyword" - id: iflet_implicitly_unwraps - msg: >- - pattern matching in a condition implicitly unwraps optionals + msg: "pattern matching in a condition implicitly unwraps optionals" - id: type_pattern_missing_is - msg: >- - 'is' keyword required to pattern match against type name + msg: "'is' keyword required to pattern match against type name" - id: pattern_type_mismatch_context - msg: >- - type annotation does not match contextual type %0 + msg: "type annotation does not match contextual type %0" - id: tuple_pattern_in_non_tuple_context - msg: >- - tuple pattern cannot match values of the non-tuple type %0 + msg: "tuple pattern cannot match values of the non-tuple type %0" - id: found_one_pattern_for_several_associated_values - msg: >- - enum case '%0' has %1 associated values; matching them as a tuple is - deprecated + msg: "enum case '%0' has %1 associated values; matching them as a tuple is deprecated" - id: converting_tuple_into_several_associated_values - msg: >- - enum case '%0' has %1 associated values + msg: "enum case '%0' has %1 associated values" - id: converting_several_associated_values_into_tuple - msg: >- - enum case '%0' has one associated value that is a tuple of %1 elements + msg: "enum case '%0' has one associated value that is a tuple of %1 elements" - id: closure_argument_list_tuple - msg: >- - contextual closure type %0 expects %1 argument%s1, but %2 - %select{were|was}3 used in closure body + msg: "contextual closure type %0 expects %1 argument%s1, but %2 %select{were|was}3 used in closure body" - id: closure_argument_list_missing - msg: >- - contextual type for closure argument list expects %0 argument%s0, which - cannot be implicitly ignored + msg: "contextual type for closure argument list expects %0 argument%s0, which cannot be implicitly ignored" - id: closure_tuple_parameter_destructuring - msg: >- - closure tuple parameter %0 does not support destructuring + msg: "closure tuple parameter %0 does not support destructuring" - id: closure_tuple_parameter_destructuring_implicit - msg: >- - closure tuple parameter %0 does not support destructuring with implicit - parameters + msg: "closure tuple parameter %0 does not support destructuring with implicit parameters" - id: single_tuple_parameter_mismatch_special - msg: >- - %0 expects a single parameter of type %1%2 + msg: "%0 expects a single parameter of type %1%2" - id: single_tuple_parameter_mismatch_normal - msg: >- - %0 %1 expects a single parameter of type %2%3 + msg: "%0 %1 expects a single parameter of type %2%3" - id: cannot_convert_single_tuple_into_multiple_arguments - msg: >- - %0 %select{%1 |}2expects %3 separate arguments%select{|; remove extra - parentheses to change tuple into separate arguments}4 + msg: "%0 %select{%1 |}2expects %3 separate arguments%select{|; remove extra parentheses to change tuple into separate arguments}4" - id: enum_element_pattern_assoc_values_mismatch - msg: >- - pattern with associated values does not match enum case %0 + msg: "pattern with associated values does not match enum case %0" - id: enum_element_pattern_assoc_values_remove - msg: >- - remove associated values to make the pattern match + msg: "remove associated values to make the pattern match" - id: tuple_pattern_length_mismatch - msg: >- - tuple pattern has the wrong length for tuple type %0 + msg: "tuple pattern has the wrong length for tuple type %0" - id: tuple_pattern_label_mismatch - msg: >- - tuple pattern element label %0 must be %1 + msg: "tuple pattern element label %0 must be %1" - id: enum_element_pattern_member_not_found - msg: >- - enum case %0 not found in type %1 + msg: "enum case %0 not found in type %1" - id: optional_element_pattern_not_valid_type - msg: >- - '?' pattern cannot match values of type %0 + msg: "'?' pattern cannot match values of type %0" - id: condition_optional_element_pattern_not_valid_type - msg: >- - initializer for conditional binding must have Optional type, not %0 + msg: "initializer for conditional binding must have Optional type, not %0" - id: enum_element_pattern_not_member_of_enum - msg: >- - enum case %0 is not a member of type %1 + msg: "enum case %0 is not a member of type %1" - id: ambiguous_enum_pattern_type - msg: >- - generic enum type %0 is ambiguous without explicit generic parameters - when matching value of type %1 + msg: "generic enum type %0 is ambiguous without explicit generic parameters when matching value of type %1" - id: type_inferred_to_undesirable_type - msg: >- - %select{variable|constant}2 %0 inferred to have type %1, which may be - unexpected + msg: "%select{variable|constant}2 %0 inferred to have type %1, which may be unexpected" - id: type_inferred_to_uninhabited_type - msg: >- - %select{variable|constant}2 %0 inferred to have type %1, which is an enum - with no cases + msg: "%select{variable|constant}2 %0 inferred to have type %1, which is an enum with no cases" - id: type_inferred_to_uninhabited_tuple_type - msg: >- - %select{variable|constant}2 %0 inferred to have type %1, which contains - an enum with no cases + msg: "%select{variable|constant}2 %0 inferred to have type %1, which contains an enum with no cases" - id: add_explicit_type_annotation_to_silence - msg: >- - add an explicit type annotation to silence this warning + msg: "add an explicit type annotation to silence this warning" - id: unowned_assignment_immediate_deallocation - msg: >- - instance will be immediately deallocated because - %select{variable|property}2 %0 is %1 + msg: "instance will be immediately deallocated because %select{variable|property}2 %0 is %1" - id: unowned_assignment_requires_strong - msg: >- - a strong reference is required to prevent the instance from being - deallocated + msg: "a strong reference is required to prevent the instance from being deallocated" - id: isa_collection_downcast_pattern_value_unimplemented - msg: >- - collection downcast in cast pattern is not implemented; use an explicit - downcast to %0 instead + msg: "collection downcast in cast pattern is not implemented; use an explicit downcast to %0 instead" - id: try_unhandled - msg: >- - errors thrown from here are not handled + msg: "errors thrown from here are not handled" - id: throwing_call_unhandled - msg: >- - call can throw, but the error is not handled + msg: "call can throw, but the error is not handled" - id: tryless_throwing_call_unhandled - msg: >- - call can throw, but it is not marked with 'try' and the error is not handled + msg: "call can throw, but it is not marked with 'try' and the error is not handled" - id: throw_in_nonthrowing_function - msg: >- - error is not handled because the enclosing function is not declared 'throws' + msg: "error is not handled because the enclosing function is not declared 'throws'" - id: throwing_call_in_rethrows_function - msg: >- - call can throw, but the error is not handled; a function declared - 'rethrows' may only throw if its parameter does + msg: "call can throw, but the error is not handled; a function declared 'rethrows' may only throw if its parameter does" - id: tryless_throwing_call_in_rethrows_function - msg: >- - call can throw, but it is not marked with 'try' and the error is not - handled; a function declared 'rethrows' may only throw if its parameter does + msg: "call can throw, but it is not marked with 'try' and the error is not handled; a function declared 'rethrows' may only throw if its parameter does" - id: throw_in_rethrows_function - msg: >- - a function declared 'rethrows' may only throw if its parameter does + msg: "a function declared 'rethrows' may only throw if its parameter does" - id: because_rethrows_argument_throws - msg: >- - call is to 'rethrows' function, but argument function can throw + msg: "call is to 'rethrows' function, but argument function can throw" - id: because_rethrows_default_argument_throws - msg: >- - call is to 'rethrows' function, but a defaulted argument function can throw + msg: "call is to 'rethrows' function, but a defaulted argument function can throw" - id: throwing_call_in_nonthrowing_autoclosure - msg: >- - call can throw, but it is executed in a non-throwing autoclosure + msg: "call can throw, but it is executed in a non-throwing autoclosure" - id: tryless_throwing_call_in_nonthrowing_autoclosure - msg: >- - call can throw, but it is not marked with 'try' and it is executed in a - non-throwing autoclosure + msg: "call can throw, but it is not marked with 'try' and it is executed in a non-throwing autoclosure" - id: throw_in_nonthrowing_autoclosure - msg: >- - error is not handled because it is thrown in a non-throwing autoclosure + msg: "error is not handled because it is thrown in a non-throwing autoclosure" - id: try_unhandled_in_nonexhaustive_catch - msg: >- - errors thrown from here are not handled because the enclosing catch is - not exhaustive + msg: "errors thrown from here are not handled because the enclosing catch is not exhaustive" - id: throwing_call_in_nonexhaustive_catch - msg: >- - call can throw, but the enclosing catch is not exhaustive + msg: "call can throw, but the enclosing catch is not exhaustive" - id: tryless_throwing_call_in_nonexhaustive_catch - msg: >- - call can throw, but it is not marked with 'try' and the enclosing catch - is not exhaustive + msg: "call can throw, but it is not marked with 'try' and the enclosing catch is not exhaustive" - id: throw_in_nonexhaustive_catch - msg: >- - error is not handled because the enclosing catch is not exhaustive + msg: "error is not handled because the enclosing catch is not exhaustive" - id: throwing_call_in_illegal_context - msg: >- - call can throw, but errors cannot be thrown out of %0 + msg: "call can throw, but errors cannot be thrown out of %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" - id: throw_in_illegal_context - msg: >- - errors cannot be thrown out of %0 + msg: "errors cannot be thrown out of %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" - id: throwing_operator_without_try - msg: >- - operator can throw but expression is not marked with 'try' + msg: "operator can throw but expression is not marked with 'try'" - id: throwing_interpolation_without_try - msg: >- - interpolation can throw but is not marked with 'try' + msg: "interpolation can throw but is not marked with 'try'" - id: throwing_call_without_try - msg: >- - call can throw but is not marked with 'try' + msg: "call can throw but is not marked with 'try'" - id: note_forgot_try - msg: >- - did you mean to use 'try'? + msg: "did you mean to use 'try'?" - id: note_error_to_optional - msg: >- - did you mean to handle error as optional value? + msg: "did you mean to handle error as optional value?" - id: note_disable_error_propagation - msg: >- - did you mean to disable error propagation? + msg: "did you mean to disable error propagation?" - id: no_throw_in_try - msg: >- - no calls to throwing functions occur within 'try' expression + msg: "no calls to throwing functions occur within 'try' expression" - id: no_throw_in_do_with_catch - msg: >- - 'catch' block is unreachable because no errors are thrown in 'do' block + msg: "'catch' block is unreachable because no errors are thrown in 'do' block" + +- id: async_call_without_await + msg: "call is 'async' but is not marked with 'await'" + +- id: async_call_without_await_in_autoclosure + msg: "call is 'async' in an autoclosure argument is not marked with 'await'" + +- id: no_async_in_await + msg: "no calls to 'async' functions occur within 'await' expression" + +- id: async_call_in_illegal_context + msg: "'async' call cannot occur in %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" + +- id: await_in_illegal_context + msg: "'await' operation cannot occur in %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" + +- id: async_in_nonasync_function + msg: "%select{'async'|'await'}0 in %select{a function|an autoclosure}1 that does not support concurrency" + +- id: note_add_async_to_function + msg: "add 'async' to function %0 to make it asynchronous" + +- id: not_objc_function_async + msg: "'async' function cannot be represented in Objective-C" + +- id: not_objc_function_type_async + msg: "'async' function types cannot be represented in Objective-C" + +- id: protocol_witness_async_conflict + msg: "candidate is %select{not |}0'async', but protocol requirement is%select{| not}0" + +- id: async_autoclosure_nonasync_function + msg: "'async' autoclosure parameter in a non-'async' function" - id: unsupported_recursive_struct - msg: >- - value type %0 cannot have a stored property that recursively contains it + msg: "value type %0 cannot have a stored property that recursively contains it" - id: enum_non_well_founded - msg: >- - enum containing only recursive cases is impossible to instantiate + msg: "enum containing only recursive cases is impossible to instantiate" - id: recursive_enum_not_indirect - msg: >- - recursive enum %0 is not marked 'indirect' + msg: "recursive enum %0 is not marked 'indirect'" - id: unsupported_infinitely_sized_type - msg: >- - value type %0 has infinite size + msg: "value type %0 has infinite size" - id: note_type_cycle_starts_here - msg: >- - cycle beginning here: %0 + msg: "cycle beginning here: %0" - id: note_recursive_enum_case_here - msg: >- - recursive case here + msg: "recursive case here" - id: sugar_type_not_found - msg: >- - broken standard library: cannot find - %select{Array|Optional|ImplicitlyUnwrappedOptional|Dictionary|Error}0 type + msg: "broken standard library: cannot find %select{Array|Optional|ImplicitlyUnwrappedOptional|Dictionary|Error}0 type" - id: optional_intrinsics_not_found - msg: >- - broken standard library: cannot find intrinsic operations on Optional + msg: "broken standard library: cannot find intrinsic operations on Optional" - id: pointer_argument_intrinsics_not_found - msg: >- - broken standard library: cannot find intrinsic operations on - UnsafeMutablePointer + msg: "broken standard library: cannot find intrinsic operations on UnsafeMutablePointer" - id: array_literal_intrinsics_not_found - msg: >- - broken standard library: cannot find intrinsic operations on Array + msg: "broken standard library: cannot find intrinsic operations on Array" - id: class_super_access - msg: >- - class %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}1|private or - fileprivate}3|cannot be declared %select{in this - context|fileprivate|internal|public|open}1}0 because its superclass - %select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses - %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 - type as a generic parameter}4 + msg: "class %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}3|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its superclass %select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 type as a generic parameter}4" - id: class_super_access_warn - msg: >- - class %select{should be declared - %select{private|fileprivate|internal|%error|%error}1|should not be declared - %select{in this context|fileprivate|internal|public|open}1}0 because its - superclass %select{is - %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses - %select{a private|a - fileprivate|an internal|an '@_spi'|an '@_spi'}2 - type as a generic parameter}4 + msg: "class %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its superclass %select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 type as a generic parameter}4" - id: class_super_not_usable_from_inline - msg: >- - %select{type referenced from |}0the superclass of a '@usableFromInline' - class must be '@usableFromInline' or public + msg: "%select{type referenced from |}0the superclass of a '@usableFromInline' class must be '@usableFromInline' or public" - id: class_super_not_usable_from_inline_warn - msg: >- - %select{type referenced from |}0the superclass of a '@usableFromInline' - class should be '@usableFromInline' or public + msg: "%select{type referenced from |}0the superclass of a '@usableFromInline' class should be '@usableFromInline' or public" - id: dot_protocol_on_non_existential - msg: >- - cannot use 'Protocol' with non-protocol type %0 + msg: "cannot use 'Protocol' with non-protocol type %0" - id: tuple_single_element - msg: >- - cannot create a single-element tuple with an element label + msg: "cannot create a single-element tuple with an element label" - id: tuple_ellipsis - msg: >- - cannot create a variadic tuple + msg: "cannot create a variadic tuple" - id: tuple_duplicate_label - msg: >- - cannot create a tuple with a duplicate element label + msg: "cannot create a tuple with a duplicate element label" - id: enum_element_ellipsis - msg: >- - variadic enum cases are not supported + msg: "variadic enum cases are not supported" - id: implicitly_unwrapped_optional_in_illegal_position_interpreted_as_optional - msg: >- - using '!' is not allowed here; treating this as '?' instead + msg: "using '!' is not allowed here; treating this as '?' instead" - id: implicitly_unwrapped_optional_deprecated_in_this_position - msg: >- - using '!' here is deprecated and will be removed in a future release + msg: "using '!' here is deprecated and will be removed in a future release" - id: implicitly_unwrapped_optional_in_illegal_position - msg: >- - using '!' is not allowed here; perhaps '?' was intended? + msg: "using '!' is not allowed here; perhaps '?' was intended?" - id: invalid_ownership_type - msg: >- - %0 may only be applied to class and class-bound protocol types, not %1 + msg: "%0 may only be applied to class and class-bound protocol types, not %1" - id: invalid_ownership_protocol_type - msg: >- - %0 must not be applied to non-class-bound %1; consider adding a protocol - conformance that has a class bound + msg: "%0 must not be applied to non-class-bound %1; consider adding a protocol conformance that has a class bound" - id: invalid_ownership_incompatible_class - msg: >- - %0 is incompatible with %1 references + msg: "%0 is incompatible with %1 references" - id: invalid_ownership_with_optional - msg: >- - %0 variable cannot have optional type + msg: "%0 variable cannot have optional type" - id: invalid_ownership_not_optional - msg: >- - %0 variable should have optional type %1 + msg: "%0 variable should have optional type %1" - id: invalid_ownership_is_let - msg: >- - %0 must be a mutable variable, because it may change at runtime + msg: "%0 must be a mutable variable, because it may change at runtime" - id: ownership_invalid_in_protocols - msg: >- - %0 cannot be applied to a property declaration in a protocol + msg: "%0 cannot be applied to a property declaration in a protocol" - id: ownership_invalid_in_protocols_compat_warning - msg: >- - %0 should not be applied to a property declaration in a protocol and will - be disallowed in future versions + msg: "%0 should not be applied to a property declaration in a protocol and will be disallowed in future versions" - id: required_initializer_nonclass - msg: >- - 'required' initializer in non-class type %0 + msg: "'required' initializer in non-class type %0" - id: required_initializer_in_extension - msg: >- - 'required' initializer must be declared directly in class %0 (not in an - extension) + msg: "'required' initializer must be declared directly in class %0 (not in an extension)" - id: required_initializer_missing - msg: >- - 'required' initializer %0 must be provided by subclass of %1 + msg: "'required' initializer %0 must be provided by subclass of %1" - id: required_initializer_here - msg: >- - 'required' initializer is declared in superclass here + msg: "'required' initializer is declared in superclass here" - id: required_initializer_not_accessible - msg: >- - 'required' initializer must be accessible wherever class %0 can be - subclassed + msg: "'required' initializer must be accessible wherever class %0 can be subclassed" - id: required_initializer_missing_keyword - msg: >- - 'required' modifier must be present on all overrides of a required - initializer + msg: "'required' modifier must be present on all overrides of a required initializer" - id: required_initializer_override_wrong_keyword - msg: >- - use the 'required' modifier to override a required initializer + msg: "use the 'required' modifier to override a required initializer" - id: required_initializer_override_keyword - msg: >- - 'override' is implied when overriding a required initializer + msg: "'override' is implied when overriding a required initializer" - id: overridden_required_initializer_here - msg: >- - overridden required initializer is here + msg: "overridden required initializer is here" - id: attribute_requires_function_type - msg: >- - @%0 attribute only applies to function types + msg: "@%0 attribute only applies to function types" - id: unsupported_convention - msg: >- - convention '%0' not supported + msg: "convention '%0' not supported" - id: unreferenced_generic_parameter - msg: >- - generic parameter '%0' is not used in function signature + msg: "generic parameter '%0' is not used in function signature" - id: unexpected_ctype_for_non_c_convention - msg: >- - convention '%0' does not support the 'cType' argument label, did you mean - @convention(c, cType: "%1") or @convention(block, cType: "%1") instead? + msg: "convention '%0' does not support the 'cType' argument label, did you mean @convention(c, cType: \"%1\") or @convention(block, cType: \"%1\") instead?" - id: unable_to_parse_c_function_type - msg: >- - unable to parse '%0'; it should be a C function pointer type or a block - pointer type + msg: "unable to parse '%0'; it should be a C function pointer type or a block pointer type" - id: unsupported_opaque_type - msg: >- - 'some' types are only implemented for the declared type of properties and - subscripts and the return type of functions + msg: "'some' types are only implemented for the declared type of properties and subscripts and the return type of functions" - id: opaque_type_unsupported_pattern - msg: >- - 'some' type can only be declared on a single property declaration + msg: "'some' type can only be declared on a single property declaration" - id: opaque_type_in_protocol_requirement - msg: >- - 'some' type cannot be the return type of a protocol requirement; - did you mean to add an associated type? + msg: "'some' type cannot be the return type of a protocol requirement; did you mean to add an associated type?" - id: attr_only_on_parameters_of_differentiable - msg: >- - '%0' may only be used on parameters of '@differentiable' function types + msg: "'%0' may only be used on parameters of '@differentiable' function types" - id: differentiable_function_type_invalid_parameter - msg: >- - parameter type '%0' does not conform to 'Differentiable'%select{| and - satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is - '@differentiable%select{|(linear)}1'%select{|; did you want to add - '@noDerivative' to this parameter?}2 + msg: "parameter type '%0' does not conform to 'Differentiable'%select{| and satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is '@differentiable%select{|(linear)}1'%select{|; did you want to add '@noDerivative' to this parameter?}2" - id: differentiable_function_type_invalid_result - msg: >- - result type '%0' does not conform to 'Differentiable'%select{| and - satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is - '@differentiable%select{|(linear)}1' + msg: "result type '%0' does not conform to 'Differentiable'%select{| and satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is '@differentiable%select{|(linear)}1'" - id: opened_non_protocol - msg: >- - @opened cannot be applied to non-protocol type %0 + msg: "@opened cannot be applied to non-protocol type %0" - id: sil_function_ellipsis - msg: >- - SIL function types cannot be variadic + msg: "SIL function types cannot be variadic" - id: sil_function_input_label - msg: >- - SIL function types cannot have labeled inputs + msg: "SIL function types cannot have labeled inputs" - id: sil_function_output_label - msg: >- - SIL function types cannot have labeled results + msg: "SIL function types cannot have labeled results" - id: sil_non_coro_yields - msg: >- - non-coroutine SIL function types cannot have @yield results + msg: "non-coroutine SIL function types cannot have @yield results" - id: sil_function_repeat_convention - msg: >- - repeated %select{parameter|result|callee}0 convention attribute + msg: "repeated %select{parameter|result|callee}0 convention attribute" - id: ast_subst_function_type - msg: >- - substitutions cannot be provided on a formal function type + msg: "substitutions cannot be provided on a formal function type" - id: sil_function_multiple_error_results - msg: >- - SIL function types cannot have multiple @error results + msg: "SIL function types cannot have multiple @error results" - id: unsupported_sil_convention - msg: >- - convention '%0' not supported in SIL + msg: "convention '%0' not supported in SIL" - id: illegal_sil_type - msg: >- - type %0 is not a legal SIL value type + msg: "type %0 is not a legal SIL value type" - id: sil_box_arg_mismatch - msg: >- - SIL box type has wrong number of generic arguments for layout + msg: "SIL box type has wrong number of generic arguments for layout" - id: sil_metatype_without_repr - msg: >- - metatypes in SIL must have @thin, @thick, or @objc_metatype attribute + msg: "metatypes in SIL must have @thin, @thick, or @objc_metatype attribute" - id: sil_metatype_multiple_reprs - msg: >- - metatypes in SIL can only be one of @thin, @thick, or @objc_metatype + msg: "metatypes in SIL can only be one of @thin, @thick, or @objc_metatype" - id: objc_interop_disabled - msg: >- - Objective-C interoperability is disabled + msg: "Objective-C interoperability is disabled" - id: attr_used_without_required_module - msg: >- - %0 attribute used without importing module %1 + msg: "%0 attribute used without importing module %1" - id: invalid_objc_decl_context - msg: >- - @objc can only be used with members of classes, @objc protocols, and - concrete extensions of classes + msg: "@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes" - id: invalid_objc_decl - msg: >- - only classes (and their extensions), protocols, methods, initializers, - properties, and subscript declarations can be declared @objc + msg: "only classes (and their extensions), protocols, methods, initializers, properties, and subscript declarations can be declared @objc" - id: invalid_objc_swift_rooted_class - msg: >- - only classes that inherit from NSObject can be declared @objc + msg: "only classes that inherit from NSObject can be declared @objc" - id: invalid_nonobjc_decl - msg: >- - only class members and extensions of classes can be declared @nonobjc + msg: "only class members and extensions of classes can be declared @nonobjc" - id: invalid_nonobjc_extension - msg: >- - only extensions of classes can be declared @nonobjc + msg: "only extensions of classes can be declared @nonobjc" - id: objc_in_extension_context - msg: >- - members of constrained extensions cannot be declared @objc + msg: "members of constrained extensions cannot be declared @objc" - id: objc_in_generic_extension - msg: >- - extensions of %select{classes from generic context|generic classes}0 - cannot contain '@objc' members + msg: "extensions of %select{classes from generic context|generic classes}0 cannot contain '@objc' members" - id: objc_in_resilient_extension - msg: >- - '@objc' %0 in extension of subclass of %1 requires %2 %3 + msg: "'@objc' %0 in extension of subclass of %1 requires %2 %3" - id: objc_operator - msg: >- - operator methods cannot be declared @objc + msg: "operator methods cannot be declared @objc" - id: objc_operator_proto - msg: >- - @objc protocols must not have operator requirements + msg: "@objc protocols must not have operator requirements" - id: objc_inference_swift3_dynamic - msg: >- - inference of '@objc' for 'dynamic' members is deprecated + msg: "inference of '@objc' for 'dynamic' members is deprecated" - id: objc_inference_swift3_objc_derived - msg: >- - inference of '@objc' for members of Objective-C-derived classes is - deprecated + msg: "inference of '@objc' for members of Objective-C-derived classes is deprecated" - id: objc_inference_swift3_addobjc - msg: >- - add '@objc' to continue exposing an Objective-C entry point (Swift 3 - behavior) + msg: "add '@objc' to continue exposing an Objective-C entry point (Swift 3 behavior)" - id: objc_inference_swift3_addnonobjc - msg: >- - add '@nonobjc' to suppress the Objective-C entry point (Swift 4 behavior) + msg: "add '@nonobjc' to suppress the Objective-C entry point (Swift 4 behavior)" - id: objc_for_generic_class - msg: >- - generic subclasses of '@objc' classes cannot have an explicit '@objc' - because they are not directly visible from Objective-C + msg: "generic subclasses of '@objc' classes cannot have an explicit '@objc' because they are not directly visible from Objective-C" - id: objc_for_resilient_class - msg: >- - explicit '@objc' on subclass of %0 requires %1 %2 + msg: "explicit '@objc' on subclass of %0 requires %1 %2" - id: objc_getter_for_nonobjc_property - msg: >- - '@objc' getter for non-'@objc' property + msg: "'@objc' getter for non-'@objc' property" - id: objc_getter_for_nonobjc_subscript - msg: >- - '@objc' getter for non-'@objc' subscript + msg: "'@objc' getter for non-'@objc' subscript" - id: objc_setter_for_nonobjc_property - msg: >- - '@objc' setter for non-'@objc' property + msg: "'@objc' setter for non-'@objc' property" - id: objc_setter_for_nonobjc_subscript - msg: >- - '@objc' setter for non-'@objc' subscript + msg: "'@objc' setter for non-'@objc' subscript" - id: accessor_swift3_objc_inference - msg: >- - %select{%0 %1|%1}2 with '@objc' %select{getter|setter}3 depends on - deprecated inference of '@objc' + msg: "%select{%0 %1|%1}2 with '@objc' %select{getter|setter}3 depends on deprecated inference of '@objc'" - id: objc_enum_generic - msg: >- - '@objc' enum cannot be generic + msg: "'@objc' enum cannot be generic" - id: objc_name_req_nullary - msg: >- - '@objc' %0 must have a simple name + msg: "'@objc' %0 must have a simple name" - id: objc_name_subscript - msg: >- - '@objc' subscript cannot have a name; did you mean to put the name on the - getter or setter? + msg: "'@objc' subscript cannot have a name; did you mean to put the name on the getter or setter?" - id: objc_name_deinit - msg: >- - '@objc' deinitializer cannot have a name + msg: "'@objc' deinitializer cannot have a name" - id: objc_name_func_mismatch - msg: >- - '@objc' %select{initializer|method}0 name provides %select{one argument - name|names for %1 arguments}2, but %select{initializer|method}0 has - %select{one parameter|%3 parameters}4%select{| - (%select{|including }4the error parameter)}5 + msg: "'@objc' %select{initializer|method}0 name provides %select{one argument name|names for %1 arguments}2, but %select{initializer|method}0 has %select{one parameter|%3 parameters}4%select{| (%select{|including }4the error parameter)}5" - id: objc_enum_case_req_name - msg: >- - attribute has no effect; cases within an '@objc' enum are already exposed - to Objective-C + msg: "attribute has no effect; cases within an '@objc' enum are already exposed to Objective-C" - id: objc_enum_case_req_objc_enum - msg: >- - '@objc' enum case is not allowed outside of an '@objc' enum + msg: "'@objc' enum case is not allowed outside of an '@objc' enum" - id: objc_enum_case_multi - msg: >- - '@objc' enum case declaration defines multiple enum cases with the same - Objective-C name + msg: "'@objc' enum case declaration defines multiple enum cases with the same Objective-C name" - id: objc_extension_not_class - msg: >- - '@objc' can only be applied to an extension of a class + msg: "'@objc' can only be applied to an extension of a class" - id: attribute_meaningless_when_nonobjc - msg: >- - '@%0' attribute is meaningless on a property that cannot be represented - in Objective-C + msg: "'@%0' attribute is meaningless on a property that cannot be represented in Objective-C" - id: objc_invalid_on_var - msg: >- - property cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because its type cannot be represented in Objective-C + msg: "property cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because its type cannot be represented in Objective-C" - id: objc_invalid_on_subscript - msg: >- - subscript cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because its type cannot be represented in Objective-C + msg: "subscript cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because its type cannot be represented in Objective-C" - id: objc_invalid_on_static_subscript - msg: >- - %0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member - of an @objc protocol|implicitly @objc|an @objc override|an implementation of - an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc - extension of a class (without @nonobjc)}1 + msg: "%0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1" - id: objc_invalid_with_generic_params - msg: >- - %0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member - of an @objc protocol|implicitly @objc|an @objc override|an implementation of - an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc - extension of a class (without @nonobjc)}1 because it has generic parameters + msg: "%0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1 because it has generic parameters" - id: objc_convention_invalid - msg: >- - %0 is not representable in Objective-C, so it cannot be used with - '@convention(%1)' + msg: "%0 is not representable in Objective-C, so it cannot be used with '@convention(%1)'" - id: paren_void_probably_void - msg: >- - when calling this function in Swift 4 or later, you must pass a '()' - tuple; did you mean for the input type to be '()'? + msg: "when calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?" - id: not_objc_empty_protocol_composition - msg: >- - 'Any' is not considered '@objc'; use 'AnyObject' instead + msg: "'Any' is not considered '@objc'; use 'AnyObject' instead" - id: not_objc_protocol - msg: >- - protocol-constrained type containing protocol %0 cannot be represented in - Objective-C + msg: "protocol-constrained type containing protocol %0 cannot be represented in Objective-C" - id: not_objc_class_constraint - msg: >- - protocol-constrained type containing class %0 cannot be represented in - Objective-C + msg: "protocol-constrained type containing class %0 cannot be represented in Objective-C" - id: not_objc_error_protocol_composition - msg: >- - protocol-constrained type containing 'Error' cannot be represented in - Objective-C + msg: "protocol-constrained type containing 'Error' cannot be represented in Objective-C" - id: not_objc_empty_tuple - msg: >- - empty tuple type cannot be represented in Objective-C + msg: "empty tuple type cannot be represented in Objective-C" - id: not_objc_tuple - msg: >- - tuples cannot be represented in Objective-C + msg: "tuples cannot be represented in Objective-C" - id: not_objc_swift_class - msg: >- - classes not annotated with @objc cannot be represented in Objective-C + msg: "classes not annotated with @objc cannot be represented in Objective-C" - id: not_objc_swift_struct - msg: >- - Swift structs cannot be represented in Objective-C + msg: "Swift structs cannot be represented in Objective-C" - id: not_objc_swift_enum - msg: >- - non-'@objc' enums cannot be represented in Objective-C + msg: "non-'@objc' enums cannot be represented in Objective-C" - id: not_objc_generic_type_param - msg: >- - generic type parameters cannot be represented in Objective-C + msg: "generic type parameters cannot be represented in Objective-C" - id: not_objc_function_type_param - msg: >- - function types cannot be represented in Objective-C unless their - parameters and returns can be + msg: "function types cannot be represented in Objective-C unless their parameters and returns can be" - id: not_objc_function_type_throwing - msg: >- - throwing function types cannot be represented in Objective-C + msg: "throwing function types cannot be represented in Objective-C" - id: objc_inferring_on_objc_protocol_member - msg: >- - inferring '@objc' because the declaration is a member of an '@objc' protocol + msg: "inferring '@objc' because the declaration is a member of an '@objc' protocol" - id: objc_overriding_objc_decl - msg: >- - overriding '@objc' %select{property|subscript|initializer|method}0 %1 here + msg: "overriding '@objc' %select{property|subscript|initializer|method}0 %1 here" - id: objc_witness_objc_requirement - msg: >- - satisfying requirement for %0 %1 in protocol %2 + msg: "satisfying requirement for %0 %1 in protocol %2" - id: witness_swift3_objc_inference - msg: >- - use of %0 %1 to satisfy a requirement of protocol %2 depends on '@objc' - inference deprecated in Swift 4 + msg: "use of %0 %1 to satisfy a requirement of protocol %2 depends on '@objc' inference deprecated in Swift 4" - id: no_opaque_return_type_of - msg: >- - unable to resolve type for _opaqueReturnTypeOf attribute + msg: "unable to resolve type for _opaqueReturnTypeOf attribute" - id: objc_observing_accessor - msg: >- - observing accessors are not allowed to be marked @objc + msg: "observing accessors are not allowed to be marked @objc" - id: objc_addressor - msg: >- - addressors are not allowed to be marked @objc + msg: "addressors are not allowed to be marked @objc" - id: objc_coroutine_accessor - msg: >- - 'read' and 'modify' accessors are not allowed to be marked @objc + msg: "'read' and 'modify' accessors are not allowed to be marked @objc" - id: objc_invalid_on_func_variadic - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because it has a variadic parameter + msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because it has a variadic parameter" - id: objc_invalid_on_func_inout - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an - @objc override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because inout parameters cannot be represented in - Objective-C + msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because inout parameters cannot be represented in Objective-C" - id: objc_invalid_on_func_param_type - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}1 because the type of the parameter %0 cannot be - represented in Objective-C + msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1 because the type of the parameter %0 cannot be represented in Objective-C" - id: objc_invalid_on_func_single_param_type - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because the type of the parameter cannot be - represented in Objective-C + msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because the type of the parameter cannot be represented in Objective-C" - id: objc_invalid_on_func_result_type - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because its result type cannot be represented in - Objective-C + msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because its result type cannot be represented in Objective-C" - id: objc_invalid_on_foreign_class - msg: >- - method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because Core Foundation types are not classes in - Objective-C + msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because Core Foundation types are not classes in Objective-C" - id: objc_invalid_on_throwing_optional_result - msg: >- - throwing method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because it returns a value of optional type %1; 'nil' - indicates failure to Objective-C + msg: "throwing method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because it returns a value of optional type %1; 'nil' indicates failure to Objective-C" - id: objc_invalid_on_throwing_result - msg: >- - throwing method cannot be %select{marked @_cdecl|marked dynamic|marked - @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked - @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc - override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because it returns a value of type %1; return 'Void' - or a type that bridges to an Objective-C class + msg: "throwing method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because it returns a value of type %1; return 'Void' or a type that bridges to an Objective-C class" - id: objc_invalid_on_failing_init - msg: >- - a failable and throwing initializer cannot be %select{marked - @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked - @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly - @objc|an @objc override|an implementation of an @objc requirement|marked - @IBInspectable|marked @GKInspectable|in an @objc extension of a class - (without @nonobjc)}0 because 'nil' indicates failure to Objective-C + msg: "a failable and throwing initializer cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because 'nil' indicates failure to Objective-C" - id: objc_in_objc_runtime_visible - msg: >- - %0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member - of an @objc protocol|implicitly @objc|an @objc override|an implementation of - an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an - @objc extension of a class (without @nonobjc)}1 because class %2 is only - visible via the Objective-C runtime + msg: "%0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1 because class %2 is only visible via the Objective-C runtime" - id: objc_override_method_selector_mismatch - msg: >- - Objective-C method has a different selector from the method it overrides - (%0 vs. %1) + msg: "Objective-C method has a different selector from the method it overrides (%0 vs. %1)" - id: objc_override_property_name_mismatch - msg: >- - Objective-C property has a different name from the property it overrides - (%0 vs. %1) + msg: "Objective-C property has a different name from the property it overrides (%0 vs. %1)" - id: objc_ambiguous_inference - msg: >- - ambiguous inference of Objective-C name for %0 %1 (%2 vs %3) + msg: "ambiguous inference of Objective-C name for %0 %1 (%2 vs %3)" - id: objc_ambiguous_inference_candidate - msg: >- - %0 (in protocol %1) provides Objective-C name %2 + msg: "%0 (in protocol %1) provides Objective-C name %2" - id: objc_ambiguous_error_convention - msg: >- - %0 overrides or implements protocol requirements for Objective-C - declarations with incompatible error argument conventions + msg: "%0 overrides or implements protocol requirements for Objective-C declarations with incompatible error argument conventions" - id: objc_ambiguous_error_convention_candidate - msg: >- - %0 provides an error argument here + msg: "%0 provides an error argument here" - id: nonlocal_bridged_to_objc - msg: >- - conformance of %0 to %1 can only be written in module %2 + msg: "conformance of %0 to %1 can only be written in module %2" - id: missing_bridging_function - msg: >- - missing - '%select{_forceBridgeFromObjectiveC|_conditionallyBridgeFromObjectiveC}0' + msg: "missing '%select{_forceBridgeFromObjectiveC|_conditionallyBridgeFromObjectiveC}0'" - id: objc_redecl - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 with Objective-C selector %4 conflicts with - %select{initializer %3|implicit initializer %3|deinitializer|implicit - deinitializer|method %3|getter for %3|subscript getter|setter - for %3|subscript setter}2 with the same Objective-C selector + msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 with Objective-C selector %4 conflicts with %select{initializer %3|implicit initializer %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript getter|setter for %3|subscript setter}2 with the same Objective-C selector" - id: objc_declared_here - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 declared here + msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 declared here" - id: objc_redecl_same - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 with Objective-C selector %2 conflicts with previous - declaration with the same Objective-C selector + msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 with Objective-C selector %2 conflicts with previous declaration with the same Objective-C selector" - id: objc_override_other - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 with Objective-C selector %4 conflicts with - %select{initializer %3|implicit initializer %3|deinitializer|implicit - deinitializer|method %3|getter for %3|subscript getter|setter for - %3|subscript setter}2 from superclass %5 with the same Objective-C selector + msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 with Objective-C selector %4 conflicts with %select{initializer %3|implicit initializer %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript getter|setter for %3|subscript setter}2 from superclass %5 with the same Objective-C selector" - id: objc_class_method_not_permitted - msg: >- - %select{initializer %1|implicit initializer %1|deinitializer|implicit - deinitializer|method %1|getter for %1|subscript getter|setter for - %1|subscript setter}0 defines Objective-C class method %2, which is not - permitted by Swift + msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 defines Objective-C class method %2, which is not permitted by Swift" - id: objc_witness_selector_mismatch - msg: >- - Objective-C method %2 provided by %select{initializer %1|implicit - initializer %1|deinitializer|implicit deinitializer|method %1|getter for - %1|subscript getter|setter for %1|subscript setter}0 does not match the - requirement's selector (%3) + msg: "Objective-C method %2 provided by %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 does not match the requirement's selector (%3)" - id: objc_optional_requirement_conflict - msg: >- - Objective-C method %4 provided by %select{initializer %1|implicit - initializer %1|deinitializer|implicit deinitializer|method %1|getter for - %1|subscript getter|setter for %1|subscript setter}0 conflicts with optional - requirement %select{initializer %3|implicit initializer - %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript - getter|setter for %3|subscript setter}2 in protocol %5 + msg: "Objective-C method %4 provided by %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 conflicts with optional requirement %select{initializer %3|implicit initializer %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript getter|setter for %3|subscript setter}2 in protocol %5" - id: objc_optional_requirement_swift_rename - msg: >- - rename %select{method|initializer|property|subscript}0 to match - requirement %1 + msg: "rename %select{method|initializer|property|subscript}0 to match requirement %1" - id: witness_non_objc - msg: >- - non-'@objc' %select{initializer %1|implicit initializer - %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript - getter|setter for %1|subscript setter}0 does not satisfy requirement of - '@objc' protocol %2 + msg: "non-'@objc' %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 does not satisfy requirement of '@objc' protocol %2" - id: witness_non_objc_optional - msg: >- - non-'@objc' %select{initializer %1|implicit initializer - %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript - getter|setter for %1|subscript setter}0 does not satisfy optional - requirement of '@objc' protocol %2 + msg: "non-'@objc' %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 does not satisfy optional requirement of '@objc' protocol %2" - id: witness_non_objc_storage - msg: >- - non-'@objc' %select{property %1|subscript}0 does not satisfy requirement - of '@objc' protocol %2 + msg: "non-'@objc' %select{property %1|subscript}0 does not satisfy requirement of '@objc' protocol %2" - id: witness_non_objc_storage_optional - msg: >- - non-'@objc' %select{property %1|subscript}0 does not satisfy optional - requirement of '@objc' protocol %2 + msg: "non-'@objc' %select{property %1|subscript}0 does not satisfy optional requirement of '@objc' protocol %2" - id: nonobjc_not_allowed - msg: >- - declaration is %select{marked @_cdecl|marked dynamic|marked @objc|marked - @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a - member of an @objc protocol|implicitly @objc|an @objc override|an - implementation of an @objc requirement|marked @IBInspectable|marked - @GKInspectable|in an @objc extension of a class (without @nonobjc)}0, - and cannot be marked @nonobjc + msg: "declaration is %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0, and cannot be marked @nonobjc" - id: borrowed_with_objc_dynamic - msg: >- - %0 cannot be '@_borrowed' if it is '@objc dynamic' + msg: "%0 cannot be '@_borrowed' if it is '@objc dynamic'" - id: borrowed_on_objc_protocol_requirement - msg: >- - %0 cannot be '@_borrowed' if it is an @objc protocol requirement + msg: "%0 cannot be '@_borrowed' if it is an @objc protocol requirement" - id: dynamic_with_transparent - msg: >- - a declaration cannot be both '@_tranparent' and 'dynamic' + msg: "a declaration cannot be both '@_tranparent' and 'dynamic'" - id: dynamic_replacement_accessor_type_mismatch - msg: >- - replaced accessor %0's type does not match + msg: "replaced accessor %0's type does not match" - id: dynamic_replacement_accessor_not_dynamic - msg: >- - replaced accessor for %0 is not marked dynamic + msg: "replaced accessor for %0 is not marked dynamic" - id: dynamic_replacement_accessor_not_explicit - msg: >- - replaced accessor - %select{get|set|_read|_modify|willSet|didSet|unsafeAddress|addressWithOwner|addressWithNativeOwner|unsafeMutableAddress|mutableAddressWithOwner|}0 - for %1 is not explicitly defined + msg: "replaced accessor %select{get|set|_read|_modify|willSet|didSet|unsafeAddress|addressWithOwner|addressWithNativeOwner|unsafeMutableAddress|mutableAddressWithOwner|}0 for %1 is not explicitly defined" - id: dynamic_replacement_function_not_dynamic - msg: >- - replaced function %0 is not marked dynamic + msg: "replaced function %0 is not marked dynamic" - id: dynamic_replacement_function_not_found - msg: >- - replaced function %0 could not be found + msg: "replaced function %0 could not be found" - id: dynamic_replacement_accessor_not_found - msg: >- - replaced accessor for %0 could not be found + msg: "replaced accessor for %0 could not be found" - id: dynamic_replacement_accessor_ambiguous - msg: >- - replaced accessor for %0 occurs in multiple places + msg: "replaced accessor for %0 occurs in multiple places" - id: dynamic_replacement_accessor_ambiguous_candidate - msg: >- - candidate accessor found in module %0 + msg: "candidate accessor found in module %0" - id: dynamic_replacement_function_of_type_not_found - msg: >- - replaced function %0 of type %1 could not be found + msg: "replaced function %0 of type %1 could not be found" - id: dynamic_replacement_found_function_of_type - msg: >- - found function %0 of type %1 + msg: "found function %0 of type %1" - id: dynamic_replacement_not_in_extension - msg: >- - dynamicReplacement(for:) of %0 is not defined in an extension or at the - file level + msg: "dynamicReplacement(for:) of %0 is not defined in an extension or at the file level" - id: dynamic_replacement_must_not_be_dynamic - msg: >- - dynamicReplacement(for:) of %0 must not be dynamic itself + msg: "dynamicReplacement(for:) of %0 must not be dynamic itself" - id: dynamic_replacement_replaced_not_objc_dynamic - msg: >- - %0 is not marked @objc dynamic + msg: "%0 is not marked @objc dynamic" - id: dynamic_replacement_replacement_not_objc_dynamic - msg: >- - %0 is marked @objc dynamic + msg: "%0 is marked @objc dynamic" - id: dynamic_replacement_replaced_constructor_is_convenience - msg: >- - replaced constructor %0 is marked as convenience + msg: "replaced constructor %0 is marked as convenience" - id: dynamic_replacement_replaced_constructor_is_not_convenience - msg: >- - replaced constructor %0 is not marked as convenience + msg: "replaced constructor %0 is not marked as convenience" - id: non_nominal_type_eraser - msg: >- - type eraser must be a class, struct, or enum + msg: "type eraser must be a class, struct, or enum" - id: type_eraser_does_not_conform - msg: >- - type eraser %0 must conform to protocol %1 + msg: "type eraser %0 must conform to protocol %1" - id: type_eraser_not_accessible - msg: >- - %select{private|fileprivate|internal|public|open}0 type eraser %1 cannot - have more restrictive access than protocol %2 (which is - %select{private|fileprivate|internal|public|open}3) + msg: "%select{private|fileprivate|internal|public|open}0 type eraser %1 cannot have more restrictive access than protocol %2 (which is %select{private|fileprivate|internal|public|open}3)" - id: type_eraser_missing_init - msg: >- - type eraser %0 must have an initializer of the form 'init(erasing: - T)' + msg: "type eraser %0 must have an initializer of the form 'init(erasing: T)'" - id: type_eraser_unviable_init - msg: >- - type eraser %0 has no viable initializer of the form 'init(erasing: T)' + msg: "type eraser %0 has no viable initializer of the form 'init(erasing: T)'" - id: type_eraser_declared_here - msg: >- - type eraser declared here + msg: "type eraser declared here" - id: type_eraser_failable_init - msg: >- - 'init(erasing:)' cannot be failable + msg: "'init(erasing:)' cannot be failable" - id: type_eraser_init_unsatisfied_requirements - msg: >- - 'init(erasing:)' cannot have unsatisfied requirements when %0 = 'some %1' + msg: "'init(erasing:)' cannot have unsatisfied requirements when %0 = 'some %1'" - id: type_eraser_init_not_accessible - msg: >- - %select{private|fileprivate|internal|public|open}0 'init(erasing:)' - cannot have more restrictive access than protocol %1 (which is - %select{private|fileprivate|internal|public|open}2) + msg: "%select{private|fileprivate|internal|public|open}0 'init(erasing:)' cannot have more restrictive access than protocol %1 (which is %select{private|fileprivate|internal|public|open}2)" - id: availability_decl_unavailable - msg: >- - %select{getter for |setter for |}0%1 is unavailable%select{ in - %3|}2%select{|: %4}4 + msg: "%select{getter for |setter for |}0%1 is unavailable%select{ in %3|}2%select{|: %4}4" - id: availability_decl_unavailable_warn - msg: >- - %select{getter for |setter for |}0%1 is unavailable%select{ in - %3|}2%select{|: %4}4 + msg: "%select{getter for |setter for |}0%1 is unavailable%select{ in %3|}2%select{|: %4}4" - id: availability_decl_unavailable_rename - msg: >- - %select{getter for |setter for |}0%1 has been %select{renamed to|replaced - by}2%select{| instance method| property}3 '%4'%select{|: %5}5 + msg: "%select{getter for |setter for |}0%1 has been %select{renamed to|replaced by}2%select{| instance method| property}3 '%4'%select{|: %5}5" - id: availability_decl_unavailable_rename_warn - msg: >- - %select{getter for |setter for |}0%1 has been %select{renamed to|replaced - by}2%select{| instance method| property}3 '%4'%select{|: %5}5 + msg: "%select{getter for |setter for |}0%1 has been %select{renamed to|replaced by}2%select{| instance method| property}3 '%4'%select{|: %5}5" - id: availability_marked_unavailable - msg: >- - %select{getter for |setter for |}0%1 has been explicitly marked - unavailable here + msg: "%select{getter for |setter for |}0%1 has been explicitly marked unavailable here" - id: availability_introduced_in_version - msg: >- - %select{getter for |setter for |}0%1 was introduced in %2 %3 + msg: "%select{getter for |setter for |}0%1 was introduced in %2 %3" - id: availability_obsoleted - msg: >- - %select{getter for |setter for |}0%1 was obsoleted in %2 %3 + msg: "%select{getter for |setter for |}0%1 was obsoleted in %2 %3" - id: availability_deprecated - msg: >- - %select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 - deprecated%select{| in %3%select{| %5}4}2%select{|: %6}6 + msg: "%select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 deprecated%select{| in %3%select{| %5}4}2%select{|: %6}6" - id: availability_deprecated_rename - msg: >- - %select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 - deprecated%select{| in %3%select{| %5}4}2: %select{renamed to|replaced - by}6%select{| instance method| property}7 '%8' + msg: "%select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 deprecated%select{| in %3%select{| %5}4}2: %select{renamed to|replaced by}6%select{| instance method| property}7 '%8'" - id: note_deprecated_rename - msg: >- - use '%0' instead + msg: "use '%0' instead" - id: availability_decl_more_than_enclosing - msg: >- - declaration cannot be more available than enclosing scope + msg: "declaration cannot be more available than enclosing scope" - id: availability_decl_more_than_enclosing_enclosing_here - msg: >- - enclosing scope here + msg: "enclosing scope here" - id: availability_decl_only_version_newer - msg: >- - %0 is only available in %1 %2 or newer + msg: "%0 is only available in %1 %2 or newer" - id: availability_opaque_types_only_version_newer - msg: >- - 'some' return types are only available in %0 %1 or newer + msg: "'some' return types are only available in %0 %1 or newer" - id: availability_guard_with_version_check - msg: >- - add 'if #available' version check + msg: "add 'if #available' version check" - id: availability_add_attribute - msg: >- - add @available attribute to enclosing %0 + msg: "add @available attribute to enclosing %0" - id: availability_accessor_only_version_newer - msg: >- - %select{getter|setter}0 for %1 is only available in %2 %3 or newer + msg: "%select{getter|setter}0 for %1 is only available in %2 %3 or newer" - id: availability_inout_accessor_only_version_newer - msg: >- - cannot pass as inout because %select{getter|setter}0 for %1 is only - available in %2 %3 or newer + msg: "cannot pass as inout because %select{getter|setter}0 for %1 is only available in %2 %3 or newer" - id: availability_query_required_for_platform - msg: >- - condition required for target platform '%0' + msg: "condition required for target platform '%0'" - id: availability_query_useless_enclosing_scope - msg: >- - unnecessary check for '%0'; enclosing scope ensures guard will always be - true + msg: "unnecessary check for '%0'; enclosing scope ensures guard will always be true" - id: availability_query_useless_enclosing_scope_here - msg: >- - enclosing scope here + msg: "enclosing scope here" - id: availability_global_script_no_potential - msg: >- - global variable cannot be marked potentially unavailable with - '@available' in script mode + msg: "global variable cannot be marked potentially unavailable with '@available' in script mode" - id: availability_stored_property_no_potential - msg: >- - stored properties cannot be marked potentially unavailable with - '@available' + msg: "stored properties cannot be marked potentially unavailable with '@available'" - id: availability_protocol_requires_version - msg: >- - protocol %0 requires %1 to be available in %2 %3 and newer + msg: "protocol %0 requires %1 to be available in %2 %3 and newer" - id: availability_protocol_requirement_here - msg: >- - protocol requirement here + msg: "protocol requirement here" - id: public_decl_needs_availability - msg: >- - public declarations should have an availability attribute when building - with -require-explicit-availability + msg: "public declarations should have an availability attribute when building with -require-explicit-availability" - id: availabilty_string_subscript_migration - msg: >- - subscripts returning String were obsoleted in Swift 4; explicitly - construct a String from subscripted result + msg: "subscripts returning String were obsoleted in Swift 4; explicitly construct a String from subscripted result" - id: discardable_result_on_void_never_function - msg: >- - @discardableResult declared on a function returning %select{Never|Void}0 - is unnecessary + msg: "@discardableResult declared on a function returning %select{Never|Void}0 is unnecessary" - id: fixed_layout_attr_on_internal_type - msg: >- - '@_fixed_layout' attribute can only be applied to '@usableFromInline' or - public declarations, but %0 is - %select{private|fileprivate|internal|%error|%error}1 + msg: "'@_fixed_layout' attribute can only be applied to '@usableFromInline' or public declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1" - id: fixed_layout_struct - msg: >- - '@frozen' attribute is now used for fixed-layout structs + msg: "'@frozen' attribute is now used for fixed-layout structs" - id: frozen_attr_on_internal_type - msg: >- - '@frozen' attribute can only be applied to '@usableFromInline' or public - declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1 + msg: "'@frozen' attribute can only be applied to '@usableFromInline' or public declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1" - id: usable_from_inline_attr_with_explicit_access - msg: >- - '@usableFromInline' attribute can only be applied to internal - declarations, but %0 is %select{private|fileprivate|%error|public|open}1 + msg: "'@usableFromInline' attribute can only be applied to internal declarations, but %0 is %select{private|fileprivate|%error|public|open}1" - id: inlinable_implies_usable_from_inline - msg: >- - '@inlinable' declaration is already '@usableFromInline' + msg: "'@inlinable' declaration is already '@usableFromInline'" - id: usable_from_inline_attr_in_protocol - msg: >- - '@usableFromInline' attribute cannot be used in protocols + msg: "'@usableFromInline' attribute cannot be used in protocols" - id: local_type_in_inlinable_function - msg: >- - type %0 cannot be nested inside %select{a '@_transparent' function|an - '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default - argument value|a property initializer in a '@frozen' type}1 + msg: "type %0 cannot be nested inside %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}1" - id: resilience_decl_unavailable - msg: >- - %select{%0|%0 for}4 %1 is - %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and cannot be - referenced from %select{a '@_transparent' function|an '@inlinable' - function|an '@_alwaysEmitIntoClient' function|a default argument value|a - property initializer in a '@frozen' type}3 + msg: "%select{%0|%0 for}4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and cannot be referenced from %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}3" - id: resilience_decl_unavailable_warn - msg: >- - %select{%0|%0 for}4 %1 is - %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and should not be - referenced from %select{a '@_transparent' function|an '@inlinable' - function|an '@_alwaysEmitIntoClient' function|a default argument value|a - property initializer in a '@frozen' type}3 + msg: "%select{%0|%0 for}4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and should not be referenced from %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}3" - id: inlinable_decl_ref_from_hidden_module - msg: >- - %0 %1 cannot be used in %select{a '@_transparent' function|an - '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default - argument value|a property initializer in a '@frozen' type}2 because - %select{%3 was imported implementation-only|it is an SPI imported from - %3|it is SPI}4 + msg: "%0 %1 cannot be used in %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}2 because %select{%3 was imported implementation-only|it is an SPI imported from %3|it is SPI}4" - id: resilience_decl_declared_here_public - msg: >- - %select{%0|%0 for}2 %1 is not public + msg: "%select{%0|%0 for}2 %1 is not public" - id: resilience_decl_declared_here - msg: >- - %select{%0|%0 for}2 %1 is not '@usableFromInline' or public + msg: "%select{%0|%0 for}2 %1 is not '@usableFromInline' or public" - id: class_designated_init_inlinable_resilient - msg: >- - initializer for class %0 is - '%select{@_transparent|@inlinable|@_alwaysEmitIntoClient|%error}1' - and must delegate to another initializer + msg: "initializer for class %0 is '%select{@_transparent|@inlinable|@_alwaysEmitIntoClient|%error}1' and must delegate to another initializer" - id: attribute_invalid_on_stored_property - msg: >- - '%0' attribute cannot be applied to stored properties + msg: "'%0' attribute cannot be applied to stored properties" - id: inlinable_dynamic_not_supported - msg: >- - '@inlinable' attribute cannot be applied to 'dynamic' declarations + msg: "'@inlinable' attribute cannot be applied to 'dynamic' declarations" - id: inlinable_decl_not_public - msg: >- - '@inlinable' attribute can only be applied to public declarations, but %0 - is %select{private|fileprivate|internal|%error|%error}1 + msg: "'@inlinable' attribute can only be applied to public declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1" - id: inlinable_resilient_deinit - msg: >- - deinitializer can only be '@inlinable' if the class is '@_fixed_layout' + msg: "deinitializer can only be '@inlinable' if the class is '@_fixed_layout'" - id: specialize_attr_nongeneric_trailing_where - msg: >- - trailing 'where' clause in '_specialize' attribute of non-generic - function %0 + msg: "trailing 'where' clause in '_specialize' attribute of non-generic function %0" - id: specialize_missing_where_clause - msg: >- - missing 'where' clause in '_specialize' attribute + msg: "missing 'where' clause in '_specialize' attribute" - id: specialize_empty_where_clause - msg: >- - empty 'where' clause in '_specialize' attribute + msg: "empty 'where' clause in '_specialize' attribute" - id: specialize_attr_non_concrete_same_type_req - msg: >- - Only concrete type same-type requirements are supported by '_specialize' - attribute + msg: "Only concrete type same-type requirements are supported by '_specialize' attribute" - id: specialize_attr_only_generic_param_req - msg: >- - Only requirements on generic parameters are supported by '_specialize' - attribute + msg: "Only requirements on generic parameters are supported by '_specialize' attribute" - id: specialize_attr_only_one_concrete_same_type_req - msg: >- - Only one concrete type should be used in the same-type requirement in - '_specialize' attribute + msg: "Only one concrete type should be used in the same-type requirement in '_specialize' attribute" - id: specialize_attr_non_protocol_type_constraint_req - msg: >- - Only conformances to protocol types are supported by '_specialize' attribute + msg: "Only conformances to protocol types are supported by '_specialize' attribute" - id: specialize_attr_type_parameter_count_mismatch - msg: >- - %select{too many|too few}2 type parameters are specified in '_specialize' - attribute (got %1, but expected %0) + msg: "%select{too many|too few}2 type parameters are specified in '_specialize' attribute (got %1, but expected %0)" - id: specialize_attr_missing_constraint - msg: >- - Missing constraint for %0 in '_specialize' attribute + msg: "Missing constraint for %0 in '_specialize' attribute" - id: specialize_attr_unsupported_kind_of_req - msg: >- - Only same-type and layout requirements are supported by '_specialize' - attribute + msg: "Only same-type and layout requirements are supported by '_specialize' attribute" - id: pbd_never_used_stmtcond - msg: >- - value %0 was defined but never used; consider replacing with boolean test + msg: "value %0 was defined but never used; consider replacing with boolean test" - id: unused_setter_parameter - msg: >- - setter argument %0 was never used, but the property was accessed + msg: "setter argument %0 was never used, but the property was accessed" - id: fixit_for_unused_setter_parameter - msg: >- - did you mean to use %0 instead of accessing the property's current value? + msg: "did you mean to use %0 instead of accessing the property's current value?" - id: pbd_never_used - msg: >- - initialization of %select{variable|immutable value}1 %0 was never used; - consider replacing with assignment to '_' or removing it + msg: "initialization of %select{variable|immutable value}1 %0 was never used; consider replacing with assignment to '_' or removing it" - id: capture_never_used - msg: >- - capture %0 was never used + msg: "capture %0 was never used" - id: variable_never_used - msg: >- - %select{variable|immutable value}1 %0 was never used; consider replacing - with '_' or removing it + msg: "%select{variable|immutable value}1 %0 was never used; consider replacing with '_' or removing it" - id: immutable_value_never_used_but_assigned - msg: >- - immutable value %0 was never used; consider removing it + msg: "immutable value %0 was never used; consider removing it" - id: variable_never_mutated - msg: >- - variable %0 was never mutated; consider %select{removing 'var' to make - it|changing to 'let'}1 constant + msg: "variable %0 was never mutated; consider %select{removing 'var' to make it|changing to 'let'}1 constant" - id: variable_never_read - msg: >- - variable %0 was written to, but never read + msg: "variable %0 was written to, but never read" - id: observe_keypath_property_not_objc_dynamic - msg: >- - passing reference to non-'@objc dynamic' property %0 to KVO method %1 may - lead to unexpected behavior or runtime trap + msg: "passing reference to non-'@objc dynamic' property %0 to KVO method %1 may lead to unexpected behavior or runtime trap" - id: default_magic_identifier_mismatch - msg: >- - parameter %0 with default argument '%1' passed to parameter %2, whose - default argument is '%3' + msg: "parameter %0 with default argument '%1' passed to parameter %2, whose default argument is '%3'" - id: change_caller_default_to_match_callee - msg: >- - did you mean for parameter %0 to default to '%1'? + msg: "did you mean for parameter %0 to default to '%1'?" - id: silence_default_magic_identifier_mismatch - msg: >- - add parentheses to silence this warning + msg: "add parentheses to silence this warning" - id: debug_long_function_body - msg: >- - %0 %1 took %2ms to type-check (limit: %3ms) + msg: "%0 %1 took %2ms to type-check (limit: %3ms)" - id: debug_long_closure_body - msg: >- - closure took %0ms to type-check (limit: %1ms) + msg: "closure took %0ms to type-check (limit: %1ms)" - id: debug_long_expression - msg: >- - expression took %0ms to type-check (limit: %1ms) + msg: "expression took %0ms to type-check (limit: %1ms)" - id: empty_switch_stmt - msg: >- - 'switch' statement body must have at least one 'case' or 'default' block; - do you want to add a default case? + msg: "'switch' statement body must have at least one 'case' or 'default' block; do you want to add a default case?" - id: non_exhaustive_switch - msg: >- - switch must be exhaustive + msg: "switch must be exhaustive" - id: possibly_non_exhaustive_switch - msg: >- - the compiler is unable to check that this switch is exhaustive in - reasonable time + msg: "the compiler is unable to check that this switch is exhaustive in reasonable time" - id: missing_several_cases - msg: >- - do you want to add %select{missing cases|a default clause}0? + msg: "do you want to add %select{missing cases|a default clause}0?" - id: missing_unknown_case - msg: >- - handle unknown values using "@unknown default" + msg: "handle unknown values using \"@unknown default\"" - id: non_exhaustive_switch_drop_unknown - msg: >- - remove '@unknown' to handle remaining values + msg: "remove '@unknown' to handle remaining values" - id: missing_particular_case - msg: >- - add missing case: '%0' + msg: "add missing case: '%0'" - id: redundant_particular_case - msg: >- - case is already handled by previous patterns; consider removing it + msg: "case is already handled by previous patterns; consider removing it" - id: redundant_particular_literal_case - msg: >- - literal value is already handled by previous pattern; consider removing it + msg: "literal value is already handled by previous pattern; consider removing it" - id: redundant_particular_literal_case_here - msg: >- - first occurrence of identical literal pattern is here + msg: "first occurrence of identical literal pattern is here" - id: non_exhaustive_switch_warn - msg: >- - switch must be exhaustive + msg: "switch must be exhaustive" - id: non_exhaustive_switch_unknown_only - msg: >- - switch covers known cases, but %0 may have additional unknown - values%select{|, possibly added in future versions}1 + msg: "switch covers known cases, but %0 may have additional unknown values%select{|, possibly added in future versions}1" - id: override_nsobject_hashvalue_error - msg: >- - 'NSObject.hashValue' is not overridable; did you mean to override - 'NSObject.hash'? + msg: "'NSObject.hashValue' is not overridable; did you mean to override 'NSObject.hash'?" - id: hashvalue_implementation - msg: >- - 'Hashable.hashValue' is deprecated as a protocol requirement; conform - type %0 to 'Hashable' by implementing 'hash(into:)' instead + msg: "'Hashable.hashValue' is deprecated as a protocol requirement; conform type %0 to 'Hashable' by implementing 'hash(into:)' instead" - id: property_wrapper_no_value_property - msg: >- - property wrapper type %0 does not contain a non-static property named %1 + msg: "property wrapper type %0 does not contain a non-static property named %1" - id: property_wrapper_ambiguous_value_property - msg: >- - property wrapper type %0 has multiple non-static properties named %1 + msg: "property wrapper type %0 has multiple non-static properties named %1" - id: property_wrapper_wrong_initial_value_init - msg: >- - %0 parameter type (%1) must be the same as its 'wrappedValue' property - type (%2) or an @autoclosure thereof + msg: "%0 parameter type (%1) must be the same as its 'wrappedValue' property type (%2) or an @autoclosure thereof" - id: property_wrapper_failable_init - msg: >- - property wrapper initializer %0 cannot be failable + msg: "property wrapper initializer %0 cannot be failable" - id: property_wrapper_type_requirement_not_accessible - msg: >- - %select{private|fileprivate|internal|public|open}0 %1 %2 cannot have more - restrictive access than its enclosing property wrapper type %3 (which is - %select{private|fileprivate|internal|public|open}4) + msg: "%select{private|fileprivate|internal|public|open}0 %1 %2 cannot have more restrictive access than its enclosing property wrapper type %3 (which is %select{private|fileprivate|internal|public|open}4)" - id: property_wrapper_ambiguous_enclosing_self_subscript - msg: >- - property wrapper type %0 has multiple enclosing-self subscripts %1 + msg: "property wrapper type %0 has multiple enclosing-self subscripts %1" - id: property_wrapper_dynamic_self_type - msg: >- - property wrapper %select{wrapped value|projected value}0 cannot have - dynamic Self type + msg: "property wrapper %select{wrapped value|projected value}0 cannot have dynamic Self type" - id: property_wrapper_attribute_not_on_property - msg: >- - property wrapper attribute %0 can only be applied to a property + msg: "property wrapper attribute %0 can only be applied to a property" - id: property_wrapper_declared_here - msg: >- - property wrapper type %0 declared here + msg: "property wrapper type %0 declared here" - id: property_wrapper_mutating_get_composed_to_get_only - msg: >- - property wrapper %0 with a mutating getter cannot be composed inside - get-only property wrapper %1 + msg: "property wrapper %0 with a mutating getter cannot be composed inside get-only property wrapper %1" - id: property_wrapper_local - msg: >- - property wrappers are not yet supported on local properties + msg: "property wrappers are not yet supported on local properties" - id: property_wrapper_top_level - msg: >- - property wrappers are not yet supported in top-level code + msg: "property wrappers are not yet supported in top-level code" - id: property_wrapper_let - msg: >- - property wrapper can only be applied to a 'var' + msg: "property wrapper can only be applied to a 'var'" - id: property_wrapper_computed - msg: >- - property wrapper cannot be applied to a computed property + msg: "property wrapper cannot be applied to a computed property" - id: property_with_wrapper_conflict_attribute - msg: >- - property %0 with a wrapper cannot also be - %select{lazy|@NSCopying|@NSManaged|weak|unowned|unmanaged}1 + msg: "property %0 with a wrapper cannot also be %select{lazy|@NSCopying|@NSManaged|weak|unowned|unmanaged}1" - id: property_wrapper_not_single_var - msg: >- - property wrapper can only apply to a single variable + msg: "property wrapper can only apply to a single variable" - id: property_with_wrapper_in_bad_context - msg: >- - %select{|non-static |non-static }1property %0 declared inside %select{a - protocol|an extension|an enum}1 cannot have a wrapper + msg: "%select{|non-static |non-static }1property %0 declared inside %select{a protocol|an extension|an enum}1 cannot have a wrapper" - id: property_with_wrapper_overrides - msg: >- - property %0 with attached wrapper cannot override another property + msg: "property %0 with attached wrapper cannot override another property" - id: property_wrapper_direct_init - msg: >- - initialize the property wrapper type directly with '(...') on the attribute + msg: "initialize the property wrapper type directly with '(...') on the attribute" - id: property_wrapper_incompatible_property - msg: >- - property type %0 does not match that of the 'wrappedValue' property of - its wrapper type %1 + msg: "property type %0 does not match that of the 'wrappedValue' property of its wrapper type %1" + +- id: wrapped_value_mismatch + msg: "property type %0 does not match 'wrappedValue' type %1" + +- id: composed_property_wrapper_mismatch + msg: "composed wrapper type %0 does not match former 'wrappedValue' type %1" - id: property_wrapper_type_access - msg: >- - %select{%select{variable|constant}0|property}1 %select{must be declared - %select{%select{private|fileprivate|internal|%error|%error}3|private or - fileprivate}4|cannot be declared %select{in this - context|fileprivate|internal|public|open}3}2 because its property wrapper - type uses %select{a private|a fileprivate|an internal|%error|%error}5 type + msg: "%select{%select{variable|constant}0|property}1 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}3}2 because its property wrapper type uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - id: property_wrapper_type_not_usable_from_inline - msg: >- - property wrapper type referenced from a '@usableFromInline' - %select{%select{variable|constant}0|property}1 must be '@usableFromInline' - or public + msg: "property wrapper type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 must be '@usableFromInline' or public" - id: property_wrapper_wrapperValue - msg: >- - property wrapper's 'wrapperValue' property should be renamed to - 'projectedValue'; use of 'wrapperValue' is deprecated + msg: "property wrapper's 'wrapperValue' property should be renamed to 'projectedValue'; use of 'wrapperValue' is deprecated" - id: property_wrapper_init_initialValue - msg: >- - property wrapper's 'init(initialValue:)' should be renamed to - 'init(wrappedValue:)'; use of 'init(initialValue:)' is deprecated + msg: "property wrapper's 'init(initialValue:)' should be renamed to 'init(wrappedValue:)'; use of 'init(initialValue:)' is deprecated" - id: property_wrapper_projection_value_missing - msg: >- - could not find projection value property %0 + msg: "could not find projection value property %0" - id: property_wrapper_missing_arg_init - msg: >- - missing argument for parameter %0 in property wrapper initializer; add - 'wrappedValue' and %0 arguments in '@%1(...)' + msg: "missing argument for parameter %0 in property wrapper initializer; add 'wrappedValue' and %0 arguments in '@%1(...)'" - id: function_builder_decl - msg: >- - closure containing a declaration cannot be used with function builder %0 + msg: "closure containing a declaration cannot be used with function builder %0" - id: note_function_builder_decl - msg: >- - closure containing a declaration cannot be used with function builder %0 + msg: "closure containing a declaration cannot be used with function builder %0" - id: function_builder_control_flow - msg: >- - closure containing control flow statement cannot be used with function - builder %0 + msg: "closure containing control flow statement cannot be used with function builder %0" - id: note_function_builder_control_flow - msg: >- - closure containing control flow statement cannot be used with function - builder %0 + msg: "closure containing control flow statement cannot be used with function builder %0" - id: function_builder_attribute_not_allowed_here - msg: >- - function builder attribute %0 can only be applied to a parameter, - function, or computed property + msg: "function builder attribute %0 can only be applied to a parameter, function, or computed property" - id: function_builder_attribute_on_storage_without_getter - msg: >- - function builder attribute %0 can only be applied to a - %select{subscript|property|constant|variable}1 if it defines a getter + msg: "function builder attribute %0 can only be applied to a %select{subscript|property|constant|variable}1 if it defines a getter" - id: function_builder_parameter_not_of_function_type - msg: >- - function builder attribute %0 can only be applied to a parameter of - function type + msg: "function builder attribute %0 can only be applied to a parameter of function type" - id: function_builder_parameter_autoclosure - msg: >- - function builder attribute %0 cannot be applied to an autoclosure parameter + msg: "function builder attribute %0 cannot be applied to an autoclosure parameter" - id: function_builder_multiple - msg: >- - only one function builder attribute can be attached to a - %select{declaration|parameter}0 + msg: "only one function builder attribute can be attached to a %select{declaration|parameter}0" - id: previous_function_builder_here - msg: >- - previous function builder specified here + msg: "previous function builder specified here" - id: function_builder_arguments - msg: >- - function builder attributes cannot have arguments + msg: "function builder attributes cannot have arguments" - id: function_builder_disabled_by_return - msg: >- - application of function builder %0 disabled by explicit 'return' - statement + msg: "application of function builder %0 disabled by explicit 'return' statement" - id: function_builder_remove_attr - msg: >- - remove the attribute to explicitly disable the function builder + msg: "remove the attribute to explicitly disable the function builder" - id: function_builder_remove_returns - msg: >- - remove 'return' statements to apply the function builder + msg: "remove 'return' statements to apply the function builder" - id: function_builder_infer_ambig - msg: >- - ambiguous function builder inferred for %0: %1 or %2 + msg: "ambiguous function builder inferred for %0: %1 or %2" - id: function_builder_infer_add_return - msg: >- - add an explicit 'return' statement to not use a function builder + msg: "add an explicit 'return' statement to not use a function builder" - id: function_builder_infer_pick_specific - msg: >- - apply function builder %0 (inferred from %select{protocol|dynamic - replacement of}1 %2) + msg: "apply function builder %0 (inferred from %select{protocol|dynamic replacement of}1 %2)" + +- id: function_builder_missing_limited_availability + msg: "function builder %0 does not implement 'buildLimitedAvailability'; this code may crash on earlier versions of the OS" - id: warn_reordering_tuple_shuffle_deprecated - msg: >- - expression shuffles the elements of this tuple; this behavior is - deprecated + msg: "expression shuffles the elements of this tuple; this behavior is deprecated" - id: differentiable_programming_attr_used_without_required_module - msg: >- - '@%0' attribute used without importing module %1 + msg: "'@%0' attribute used without importing module %1" - id: oslog_arg_must_be_bool_literal - msg: >- - argument must be a bool literal + msg: "argument must be a bool literal" - id: oslog_arg_must_be_integer_literal - msg: >- - argument must be an integer literal + msg: "argument must be an integer literal" - id: oslog_arg_must_be_string_literal - msg: >- - argument must be a string literal + msg: "argument must be a string literal" - id: oslog_arg_must_be_float_literal - msg: >- - argument must be a floating-point literal + msg: "argument must be a floating-point literal" - id: oslog_arg_must_be_metatype_literal - msg: >- - argument must be a .self + msg: "argument must be a .self" - id: oslog_arg_must_be_closure - msg: >- - argument must be a closure + msg: "argument must be a closure" - id: argument_must_be_constant - msg: >- - argument must be an expression with only literals + msg: "argument must be an expression with only literals" - id: oslog_message_must_be_string_interpolation - msg: >- - argument must be a string interpolation + msg: "argument must be a string interpolation" - id: oslog_arg_must_be_enum_case - msg: >- - argument must be a case of enum %0 + msg: "argument must be a case of enum %0" - id: oslog_arg_must_be_type_member_access - msg: >- - argument must be a static method or property of %0 + msg: "argument must be a static method or property of %0" - id: atomics_ordering_must_be_constant - msg: >- - ordering argument must be a static method or property of %0 + msg: "ordering argument must be a static method or property of %0" - id: warning_from_clang - msg: >- - %0 + msg: "%0" - id: error_from_clang - msg: >- - %0 + msg: "%0" - id: note_from_clang - msg: >- - %0 + msg: "%0" - id: remark_from_clang - msg: >- - %0 + msg: "%0" - id: clang_cannot_build_module - msg: >- - could not build %select{C|Objective-C}0 module '%1' + msg: "could not build %select{C|Objective-C}0 module '%1'" - id: bridging_header_missing - msg: >- - bridging header '%0' does not exist + msg: "bridging header '%0' does not exist" - id: bridging_header_error - msg: >- - failed to import bridging header '%0' + msg: "failed to import bridging header '%0'" - id: could_not_rewrite_bridging_header - msg: >- - failed to serialize bridging header; target may not be debuggable outside - of its original project + msg: "failed to serialize bridging header; target may not be debuggable outside of its original project" - id: bridging_header_pch_error - msg: >- - failed to emit precompiled header '%0' for bridging header '%1' + msg: "failed to emit precompiled header '%0' for bridging header '%1'" - id: emit_pcm_error - msg: >- - failed to emit precompiled module '%0' for module map '%1' + msg: "failed to emit precompiled module '%0' for module map '%1'" - id: dump_pcm_error - msg: >- - failed to dump precompiled module '%0' + msg: "failed to dump precompiled module '%0'" - id: invalid_swift_name_method - msg: >- - too %select{few|many}0 parameters in swift_name attribute (expected %1; - got %2) + msg: "too %select{few|many}0 parameters in swift_name attribute (expected %1; got %2)" - id: note_while_importing - msg: >- - while importing '%0' + msg: "while importing '%0'" - id: swift_name_protocol_static - msg: >- - swift_name cannot be used to define %select{static member|init}0 on - protocol + msg: "swift_name cannot be used to define %select{static member|init}0 on protocol" - id: swift_name_no_prototype - msg: >- - swift_name cannot be used on a non-prototyped function declaration + msg: "swift_name cannot be used on a non-prototyped function declaration" - id: inconsistent_swift_name - msg: >- - inconsistent Swift name for Objective-C %select{method|property}0 '%1' in - '%2' (%3 in '%4' vs. %5 in '%6') + msg: "inconsistent Swift name for Objective-C %select{method|property}0 '%1' in '%2' (%3 in '%4' vs. %5 in '%6')" - id: unresolvable_clang_decl - msg: >- - imported declaration '%0' could not be mapped to '%1' + msg: "imported declaration '%0' could not be mapped to '%1'" - id: unresolvable_clang_decl_is_a_framework_bug - msg: >- - please report this issue to the owners of '%0' + msg: "please report this issue to the owners of '%0'" - id: implicit_bridging_header_imported_from_module - msg: >- - implicit import of bridging header '%0' via module %1 is deprecated and - will be removed in a later version of Swift + msg: "implicit import of bridging header '%0' via module %1 is deprecated and will be removed in a later version of Swift" - id: bridging_module_missing - msg: >- - unable to find module '%0' for implicit conversion function '%0.%1' + msg: "unable to find module '%0' for implicit conversion function '%0.%1'" - id: bridging_function_missing - msg: >- - unable to find implicit conversion function '%0.%1' + msg: "unable to find implicit conversion function '%0.%1'" - id: bridging_function_overloaded - msg: >- - multiple definitions of implicit conversion function '%0.%1' + msg: "multiple definitions of implicit conversion function '%0.%1'" - id: bridging_function_not_function - msg: >- - definition of implicit conversion function '%0.%1' is not a function + msg: "definition of implicit conversion function '%0.%1' is not a function" - id: bridging_function_not_correct_type - msg: >- - definition of implicit conversion function '%0.%1' is not of the correct - type + msg: "definition of implicit conversion function '%0.%1' is not of the correct type" - id: bridging_objcbridgeable_missing - msg: >- - cannot find definition of '_ObjectiveCBridgeable' protocol + msg: "cannot find definition of '_ObjectiveCBridgeable' protocol" - id: bridging_objcbridgeable_broken - msg: >- - broken definition of '_ObjectiveCBridgeable' protocol: missing %0 + msg: "broken definition of '_ObjectiveCBridgeable' protocol: missing %0" - id: invalid_sil_builtin - msg: >- - INTERNAL ERROR: invalid use of builtin: %0 + msg: "INTERNAL ERROR: invalid use of builtin: %0" - id: could_not_find_bridge_type - msg: >- - could not find Objective-C bridge type for type %0; did you forget to - import Foundation? + msg: "could not find Objective-C bridge type for type %0; did you forget to import Foundation?" - id: could_not_find_pointer_pointee_property - msg: >- - could not find 'pointee' property of pointer type %0 + msg: "could not find 'pointee' property of pointer type %0" - id: writeback_overlap_property - msg: >- - inout writeback to computed property %0 occurs in multiple arguments to - call, introducing invalid aliasing + msg: "inout writeback to computed property %0 occurs in multiple arguments to call, introducing invalid aliasing" - id: writeback_overlap_subscript - msg: >- - inout writeback through subscript occurs in multiple arguments to call, - introducing invalid aliasing + msg: "inout writeback through subscript occurs in multiple arguments to call, introducing invalid aliasing" - id: writebackoverlap_note - msg: >- - concurrent writeback occurred here + msg: "concurrent writeback occurred here" - id: inout_argument_alias - msg: >- - inout arguments are not allowed to alias each other + msg: "inout arguments are not allowed to alias each other" - id: previous_inout_alias - msg: >- - previous aliasing argument + msg: "previous aliasing argument" - id: unimplemented_generator_witnesses - msg: >- - protocol conformance emission for generator coroutines is unimplemented + msg: "protocol conformance emission for generator coroutines is unimplemented" - id: exclusivity_access_required - msg: >- - overlapping accesses to %0, but - %select{initialization|read|modification|deinitialization}1 requires - exclusive access; %select{consider copying to a local variable|consider - calling MutableCollection.swapAt(_:_:)}2 + msg: "overlapping accesses to %0, but %select{initialization|read|modification|deinitialization}1 requires exclusive access; %select{consider copying to a local variable|consider calling MutableCollection.swapAt(_:_:)}2" - id: exclusivity_access_required_unknown_decl - msg: >- - overlapping accesses, but - %select{initialization|read|modification|deinitialization}0 - requires exclusive access; consider copying to a local variable + msg: "overlapping accesses, but %select{initialization|read|modification|deinitialization}0 requires exclusive access; consider copying to a local variable" - id: exclusivity_conflicting_access - msg: >- - conflicting access is here + msg: "conflicting access is here" - id: unsupported_c_function_pointer_conversion - msg: >- - C function pointer signature %0 is not compatible with expected type %1 + msg: "C function pointer signature %0 is not compatible with expected type %1" - id: c_function_pointer_from_function_with_context - msg: >- - a C function pointer cannot be formed from a %select{local - function|closure}0 that captures %select{context|generic parameters|dynamic - Self type}1 + msg: "a C function pointer cannot be formed from a %select{local function|closure}0 that captures %select{context|generic parameters|dynamic Self type}1" - id: objc_selector_malformed - msg: >- - the type ObjectiveC.Selector is malformed + msg: "the type ObjectiveC.Selector is malformed" - id: capture_before_declaration - msg: >- - closure captures %0 before it is declared + msg: "closure captures %0 before it is declared" - id: capture_before_declaration_defer - msg: >- - 'defer' block captures %0 before it is declared + msg: "'defer' block captures %0 before it is declared" - id: captured_value_declared_here - msg: >- - captured value declared here + msg: "captured value declared here" - id: escaping_inout_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures 'inout' - parameter %1 + msg: "escaping %select{local function|closure|autoclosure}0 captures 'inout' parameter %1" - id: inout_param_defined_here - msg: >- - parameter %0 is declared 'inout' + msg: "parameter %0 is declared 'inout'" - id: escaping_mutable_self_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures mutating - 'self' parameter + msg: "escaping %select{local function|closure|autoclosure}0 captures mutating 'self' parameter" - id: escaping_noescape_param_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures - non-escaping parameter %1 + msg: "escaping %select{local function|closure|autoclosure}0 captures non-escaping parameter %1" - id: noescape_param_defined_here - msg: >- - parameter %0 is implicitly non-escaping + msg: "parameter %0 is implicitly non-escaping" - id: escaping_noescape_var_capture - msg: >- - escaping %select{local function|closure|autoclosure}0 captures - non-escaping value + msg: "escaping %select{local function|closure|autoclosure}0 captures non-escaping value" - id: value_captured_here - msg: >- - captured here + msg: "captured here" - id: copy_inout_captured_by_autoclosure - msg: >- - pass a copy of %0 + msg: "pass a copy of %0" - id: copy_self_captured_by_autoclosure - msg: >- - pass a copy of 'self' + msg: "pass a copy of 'self'" - id: value_captured_transitively - msg: >- - captured indirectly by this call + msg: "captured indirectly by this call" - id: err_noescape_param_call - msg: >- - passing a %select{|closure which captures a }1non-escaping function - parameter %0 to a call to a non-escaping function parameter can allow - re-entrant modification of a variable + msg: "passing a %select{|closure which captures a }1non-escaping function parameter %0 to a call to a non-escaping function parameter can allow re-entrant modification of a variable" - id: variable_defined_here - msg: >- - %select{variable|constant}0 defined here + msg: "%select{variable|constant}0 defined here" - id: variable_used_before_initialized - msg: >- - %select{variable|constant}1 '%0' used before being initialized + msg: "%select{variable|constant}1 '%0' used before being initialized" - id: variable_inout_before_initialized - msg: >- - %select{variable|constant}1 '%0' passed by reference before being - initialized + msg: "%select{variable|constant}1 '%0' passed by reference before being initialized" - id: variable_closure_use_uninit - msg: >- - %select{variable|constant}1 '%0' captured by a closure before being - initialized + msg: "%select{variable|constant}1 '%0' captured by a closure before being initialized" - id: variable_defer_use_uninit - msg: >- - %select{variable|constant}1 '%0' used in defer before being initialized + msg: "%select{variable|constant}1 '%0' used in defer before being initialized" - id: self_closure_use_uninit - msg: >- - 'self' captured by a closure before all members were initialized + msg: "'self' captured by a closure before all members were initialized" - id: variable_addrtaken_before_initialized - msg: >- - address of %select{variable|constant}1 '%0' taken before it is initialized + msg: "address of %select{variable|constant}1 '%0' taken before it is initialized" - id: ivar_not_initialized_at_superinit - msg: >- - property '%0' not initialized at super.init call + msg: "property '%0' not initialized at super.init call" - id: ivar_not_initialized_at_implicit_superinit - msg: >- - property '%0' not initialized at implicitly generated super.init call + msg: "property '%0' not initialized at implicitly generated super.init call" - id: self_use_before_fully_init - msg: >- - 'self' used in %select{method call|property access}1 %0 before - %select{all stored properties are initialized|'super.init' call|'self.init' - call}2 + msg: "'self' used in %select{method call|property access}1 %0 before %select{all stored properties are initialized|'super.init' call|'self.init' call}2" - id: use_of_self_before_fully_init - msg: >- - 'self' used before all stored properties are initialized + msg: "'self' used before all stored properties are initialized" - id: stored_property_not_initialized - msg: >- - '%0' not initialized + msg: "'%0' not initialized" - id: selfinit_multiple_times - msg: >- - '%select{super|self}0.init' called multiple times in initializer + msg: "'%select{super|self}0.init' called multiple times in initializer" - id: superselfinit_not_called_before_return - msg: >- - '%select{super|self}0.init' isn't called on all paths before returning - from initializer + msg: "'%select{super|self}0.init' isn't called on all paths before returning from initializer" - id: self_before_superinit - msg: >- - 'self' used before 'super.init' call + msg: "'self' used before 'super.init' call" - id: self_before_selfinit - msg: >- - 'self' used before 'self.init' call + msg: "'self' used before 'self.init' call" - id: self_before_selfinit_value_type - msg: >- - 'self' used before 'self.init' call or assignment to 'self' + msg: "'self' used before 'self.init' call or assignment to 'self'" - id: self_inside_catch_superselfinit - msg: >- - 'self' used inside 'catch' block reachable from %select{super|self}0.init - call + msg: "'self' used inside 'catch' block reachable from %select{super|self}0.init call" - id: return_from_init_without_initing_stored_properties - msg: >- - return from initializer without initializing all stored properties + msg: "return from initializer without initializing all stored properties" - id: variable_function_use_uninit - msg: >- - %select{variable|constant}1 '%0' used by function definition before being - initialized + msg: "%select{variable|constant}1 '%0' used by function definition before being initialized" - id: struct_not_fully_initialized - msg: >- - struct '%0' must be completely initialized before a member is stored to + msg: "struct '%0' must be completely initialized before a member is stored to" - id: immutable_property_already_initialized - msg: >- - immutable value '%0' may only be initialized once + msg: "immutable value '%0' may only be initialized once" - id: initial_value_provided_in_let_decl - msg: >- - initial value already provided in 'let' declaration + msg: "initial value already provided in 'let' declaration" - id: mutation_of_property_of_immutable_value - msg: >- - cannot mutate %select{property %0|subscript}1 of immutable value '%2' + msg: "cannot mutate %select{property %0|subscript}1 of immutable value '%2'" - id: using_mutating_accessor_on_immutable_value - msg: >- - mutating accessor for %select{property %0|subscript}1 may not be used on - immutable value '%2' + msg: "mutating accessor for %select{property %0|subscript}1 may not be used on immutable value '%2'" - id: mutating_method_called_on_immutable_value - msg: >- - mutating %select{method|operator}1 %0 may not be used on immutable value - '%2' + msg: "mutating %select{method|operator}1 %0 may not be used on immutable value '%2'" - id: immutable_value_passed_inout - msg: >- - immutable value '%0' must not be passed inout + msg: "immutable value '%0' must not be passed inout" - id: assignment_to_immutable_value - msg: >- - immutable value '%0' must not be assigned to + msg: "immutable value '%0' must not be assigned to" - id: designated_init_in_cross_module_extension - msg: >- - initializer for struct %0 must use "self.init(...)" or "self = - ..."%select{| on all paths}1 because %select{it is not in module %2|the - struct was imported from C}3 + msg: "initializer for struct %0 must use \"self.init(...)\" or \"self = ...\"%select{| on all paths}1 because %select{it is not in module %2|the struct was imported from C}3" - id: designated_init_c_struct_fix - msg: >- - use "self.init()" to initialize the struct with zero values + msg: "use \"self.init()\" to initialize the struct with zero values" - id: missing_return - msg: >- - missing return in a %select{function|closure}1 expected to return %0 + msg: "missing return in a %select{function|closure}1 expected to return %0" - id: missing_return_last_expr - msg: >- - missing return in a %select{function|closure}1 expected to return %0; - did you mean to return the last expression? + msg: "missing return in a %select{function|closure}1 expected to return %0; did you mean to return the last expression?" - id: missing_never_call - msg: >- - %select{function|closure}1 with uninhabited return type %0 is missing - call to another never-returning function on all paths + msg: "%select{function|closure}1 with uninhabited return type %0 is missing call to another never-returning function on all paths" - id: guard_body_must_not_fallthrough - msg: >- - 'guard' body must not fall through, consider using a 'return' or 'throw' - to exit the scope + msg: "'guard' body must not fall through, consider using a 'return' or 'throw' to exit the scope" - id: unreachable_code - msg: >- - will never be executed + msg: "will never be executed" - id: unreachable_code_uninhabited_param_note - msg: >- - '%0' is uninhabited, so this function body can never be executed + msg: "'%0' is uninhabited, so this function body can never be executed" - id: unreachable_code_branch - msg: >- - condition always evaluates to %select{false|true}0 + msg: "condition always evaluates to %select{false|true}0" - id: call_to_noreturn_note - msg: >- - a call to a never-returning function + msg: "a call to a never-returning function" - id: unreachable_code_after_stmt - msg: >- - code after '%select{return|break|continue|throw}0' will never be executed + msg: "code after '%select{return|break|continue|throw}0' will never be executed" - id: unreachable_case - msg: >- - %select{case|default}0 will never be executed + msg: "%select{case|default}0 will never be executed" - id: switch_on_a_constant - msg: >- - switch condition evaluates to a constant + msg: "switch condition evaluates to a constant" - id: unreachable_code_note - msg: >- - will never be executed + msg: "will never be executed" - id: warn_infinite_recursive_function - msg: >- - all paths through this function will call itself + msg: "all paths through this function will call itself" - id: circular_transparent - msg: >- - inlining 'transparent' functions forms circular loop + msg: "inlining 'transparent' functions forms circular loop" - id: note_while_inlining - msg: >- - while inlining here + msg: "while inlining here" - id: cannot_prespecialize - msg: >- - Cannot pre-specialize %0 + msg: "Cannot pre-specialize %0" - id: missing_prespecialization - msg: >- - Pre-specialized function %0 missing in SwiftOnoneSupport module + msg: "Pre-specialized function %0 missing in SwiftOnoneSupport module" - id: integer_conversion_overflow - msg: >- - integer overflows when converted from %0 to %1 + msg: "integer overflows when converted from %0 to %1" - id: integer_conversion_overflow_builtin_types - msg: >- - integer overflows when converted from %select{unsigned|signed}0 %1 to - %select{unsigned|signed}2 %3 + msg: "integer overflows when converted from %select{unsigned|signed}0 %1 to %select{unsigned|signed}2 %3" - id: integer_conversion_overflow_warn - msg: >- - integer overflows when converted from %0 to %1 + msg: "integer overflows when converted from %0 to %1" - id: negative_integer_literal_overflow_unsigned - msg: >- - negative integer '%1' overflows when stored into unsigned type %0 + msg: "negative integer '%1' overflows when stored into unsigned type %0" - id: integer_literal_overflow - msg: >- - integer literal '%1' overflows when stored into %0 + msg: "integer literal '%1' overflows when stored into %0" - id: integer_literal_overflow_builtin_types - msg: >- - integer literal '%2' overflows when stored into %select{unsigned|signed}0 %1 + msg: "integer literal '%2' overflows when stored into %select{unsigned|signed}0 %1" - id: integer_literal_overflow_warn - msg: >- - integer literal overflows when stored into %0 + msg: "integer literal overflows when stored into %0" - id: arithmetic_operation_overflow - msg: >- - arithmetic operation '%0 %1 %2' (on type %3) results in an overflow + msg: "arithmetic operation '%0 %1 %2' (on type %3) results in an overflow" - id: arithmetic_operation_overflow_generic_type - msg: >- - arithmetic operation '%0 %1 %2' (on %select{unsigned|signed}3 %4-bit - integer type) results in an overflow + msg: "arithmetic operation '%0 %1 %2' (on %select{unsigned|signed}3 %4-bit integer type) results in an overflow" - id: division_overflow - msg: >- - division '%0 %1 %2' results in an overflow + msg: "division '%0 %1 %2' results in an overflow" - id: division_by_zero - msg: >- - division by zero + msg: "division by zero" - id: wrong_non_negative_assumption - msg: >- - assumed non-negative value '%0' is negative + msg: "assumed non-negative value '%0' is negative" - id: shifting_all_significant_bits - msg: >- - shift amount is greater than or equal to type size in bits + msg: "shift amount is greater than or equal to type size in bits" - id: static_report_error - msg: >- - static report error + msg: "static report error" - id: pound_assert_condition_not_constant - msg: >- - #assert condition not constant + msg: "#assert condition not constant" - id: pound_assert_failure - msg: >- - %0 + msg: "%0" - id: constexpr_unknown_reason_default - msg: >- - cannot evaluate expression as constant here + msg: "cannot evaluate expression as constant here" - id: constexpr_unevaluable_operation - msg: >- - cannot constant evaluate operation%select{| used by this call}0 + msg: "cannot constant evaluate operation%select{| used by this call}0" - id: constexpr_too_many_instructions - msg: >- - exceeded instruction limit: %0 when evaluating the expression at compile - time + msg: "exceeded instruction limit: %0 when evaluating the expression at compile time" - id: constexpr_limit_exceeding_instruction - msg: >- - limit exceeded %select{here|during this call}0 + msg: "limit exceeded %select{here|during this call}0" - id: constexpr_loop_found_note - msg: >- - control-flow loop found during evaluation + msg: "control-flow loop found during evaluation " - id: constexpr_loop_instruction - msg: >- - found loop %select{here|inside this call}0 + msg: "found loop %select{here|inside this call}0" - id: constexpr_overflow - msg: >- - integer overflow detected + msg: "integer overflow detected" - id: constexpr_overflow_operation - msg: >- - operation%select{| performed during this call}0 overflows + msg: "operation%select{| performed during this call}0 overflows" - id: constexpr_trap - msg: >- - %0 + msg: "%0" - id: constexpr_trap_operation - msg: >- - operation%select{| performed during this call}0 traps + msg: "operation%select{| performed during this call}0 traps" - id: constexpr_invalid_operand_seen - msg: >- - operation with invalid operands encountered during evaluation + msg: "operation with invalid operands encountered during evaluation" - id: constexpr_operand_invalid_here - msg: >- - operation with invalid operands encountered %select{here|during this call}0 + msg: "operation with invalid operands encountered %select{here|during this call}0" - id: constexpr_value_unknown_at_top_level - msg: >- - cannot evaluate top-level value as constant here + msg: "cannot evaluate top-level value as constant here" - id: constexpr_multiple_writers_found_at_top_level - msg: >- - top-level value has multiple assignments + msg: "top-level value has multiple assignments" - id: constexpr_unsupported_instruction_found - msg: >- - encountered operation not supported by the evaluator: %0 + msg: "encountered operation not supported by the evaluator: %0" - id: constexpr_unsupported_instruction_found_here - msg: >- - operation%select{| used by this call is}0 not supported by the evaluator + msg: "operation%select{| used by this call is}0 not supported by the evaluator" - id: constexpr_found_callee_with_no_body - msg: >- - encountered call to '%0' whose body is not available. Imported functions - must be marked '@inlinable' to constant evaluate + msg: "encountered call to '%0' whose body is not available. Imported functions must be marked '@inlinable' to constant evaluate" - id: constexpr_callee_with_no_body - msg: >- - %select{|calls a }0function whose body is not available + msg: "%select{|calls a }0function whose body is not available" - id: constexpr_found_call_with_unknown_arg - msg: >- - encountered call to '%0' where the %1 argument is not a constant + msg: "encountered call to '%0' where the %1 argument is not a constant" - id: constexpr_call_with_unknown_arg - msg: >- - %select{|makes a }0function call with non-constant arguments + msg: "%select{|makes a }0function call with non-constant arguments" - id: constexpr_untracked_sil_value_use_found - msg: >- - encountered use of a variable not tracked by the evaluator + msg: "encountered use of a variable not tracked by the evaluator" - id: constexpr_untracked_sil_value_used_here - msg: >- - untracked variable used %select{here|by this call}0 + msg: "untracked variable used %select{here|by this call}0" - id: constexpr_unevaluable_cast_found - msg: >- - encountered an unevaluable cast + msg: "encountered an unevaluable cast" - id: constexpr_unevaluable_cast_used_here - msg: >- - unevaluable cast encountered %select{here|by this call}0 + msg: "unevaluable cast encountered %select{here|by this call}0" - id: constexpr_unresolvable_witness_call - msg: >- - encountered unresolvable witness method call: '%0' + msg: "encountered unresolvable witness method call: '%0'" - id: constexpr_no_witness_table_entry - msg: >- - cannot find witness table entry %select{for this call|for a - witness-method invoked during this call}0 + msg: "cannot find witness table entry %select{for this call|for a witness-method invoked during this call}0" - id: constexpr_witness_call_with_no_conformance - msg: >- - cannot find concrete conformance %select{for this call|for a - witness-method invoked during this call}0 + msg: "cannot find concrete conformance %select{for this call|for a witness-method invoked during this call}0" - id: constexpr_unknown_control_flow_due_to_skip - msg: >- - branch depends on non-constant value produced by an unevaluated - instructions + msg: "branch depends on non-constant value produced by an unevaluated instructions" - id: constexpr_returned_by_unevaluated_instruction - msg: >- - result of an unevaluated instruction is not a constant + msg: "result of an unevaluated instruction is not a constant" - id: constexpr_mutated_by_unevaluated_instruction - msg: >- - value mutable by an unevaluated instruction is not a constant + msg: "value mutable by an unevaluated instruction is not a constant" - id: not_constant_evaluable - msg: >- - not constant evaluable + msg: "not constant evaluable" - id: constexpr_imported_func_not_onone - msg: >- - imported constant evaluable function '%0' must be annotated - '@_optimize(none)' + msg: "imported constant evaluable function '%0' must be annotated '@_optimize(none)'" - id: autodiff_internal_swift_not_imported - msg: >- - Automatic differentiation internal error: the Swift module is not - imported + msg: "Automatic differentiation internal error: the Swift module is not imported" - id: autodiff_differentiation_module_not_imported - msg: >- - Automatic differentiation requires the '_Differentiation' module to be - imported + msg: "Automatic differentiation requires the '_Differentiation' module to be imported" - id: autodiff_conversion_to_linear_function_not_supported - msg: >- - conversion to '@differentiable(linear)' function type is not yet - supported + msg: "conversion to '@differentiable(linear)' function type is not yet supported" - id: autodiff_function_not_differentiable_error - msg: >- - function is not differentiable + msg: "function is not differentiable" - id: autodiff_expression_not_differentiable_error - msg: >- - expression is not differentiable + msg: "expression is not differentiable" - id: autodiff_expression_not_differentiable_note - msg: >- - expression is not differentiable + msg: "expression is not differentiable" - id: autodiff_when_differentiating_function_call - msg: >- - when differentiating this function call + msg: "when differentiating this function call" - id: autodiff_when_differentiating_function_definition - msg: >- - when differentiating this function definition + msg: "when differentiating this function definition" - id: autodiff_implicitly_inherited_differentiable_attr_here - msg: >- - differentiability required by the corresponding protocol requirement here + msg: "differentiability required by the corresponding protocol requirement here" - id: autodiff_jvp_control_flow_not_supported - msg: >- - forward-mode differentiation does not yet support control flow + msg: "forward-mode differentiation does not yet support control flow" - id: autodiff_control_flow_not_supported - msg: >- - cannot differentiate unsupported control flow + msg: "cannot differentiate unsupported control flow" - id: autodiff_missing_return - msg: >- - missing return for differentiation + msg: "missing return for differentiation" - id: autodiff_external_nondifferentiable_function - msg: >- - cannot differentiate functions that have not been marked - '@differentiable' and that are defined in other files + msg: "cannot differentiate functions that have not been marked '@differentiable' and that are defined in other files" - id: autodiff_opaque_function_not_differentiable - msg: >- - opaque non-'@differentiable' function is not differentiable + msg: "opaque non-'@differentiable' function is not differentiable" - id: autodiff_private_derivative_from_fragile - msg: >- - differentiated functions in %select{'@inlinable' functions|default - arguments}0 must be marked '@differentiable' or have a public - '@derivative'%select{|; this is not possible with a closure, make a - top-level function instead}1 + msg: "differentiated functions in %select{'@inlinable' functions|default arguments}0 must be marked '@differentiable' or have a public '@derivative'%select{|; this is not possible with a closure, make a top-level function instead}1" - id: autodiff_function_noderivative_parameter_not_differentiable - msg: >- - cannot differentiate with respect to a '@noDerivative' parameter + msg: "cannot differentiate with respect to a '@noDerivative' parameter" - id: autodiff_function_assoc_func_unmet_requirements - msg: >- - function call is not differentiable because generic requirements are not - met: '%0' + msg: "function call is not differentiable because generic requirements are not met: '%0'" - id: autodiff_nondifferentiable_argument - msg: >- - cannot differentiate through a non-differentiable argument; do you want - to use 'withoutDerivative(at:)'? + msg: "cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?" - id: autodiff_nondifferentiable_result - msg: >- - cannot differentiate through a non-differentiable result; do you want to - use 'withoutDerivative(at:)'? + msg: "cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?" - id: autodiff_protocol_member_not_differentiable - msg: >- - member is not differentiable because the corresponding protocol - requirement is not '@differentiable' + msg: "member is not differentiable because the corresponding protocol requirement is not '@differentiable'" - id: autodiff_class_member_not_differentiable - msg: >- - member is not differentiable because the corresponding class member is - not '@differentiable' + msg: "member is not differentiable because the corresponding class member is not '@differentiable'" - id: autodiff_member_subset_indices_not_differentiable - msg: >- - member is differentiable only with respect to a smaller subset of arguments + msg: "member is differentiable only with respect to a smaller subset of arguments" - id: autodiff_cannot_param_subset_thunk_partially_applied_orig_fn - msg: >- - cannot convert a direct method reference to a '@differentiable' function; - use an explicit closure instead + msg: "cannot convert a direct method reference to a '@differentiable' function; use an explicit closure instead" - id: autodiff_cannot_differentiate_through_multiple_results - msg: >- - cannot differentiate through multiple results + msg: "cannot differentiate through multiple results" - id: autodiff_cannot_differentiate_through_inout_arguments - msg: >- - cannot differentiate through 'inout' arguments + msg: "cannot differentiate through 'inout' arguments" - id: autodiff_enums_unsupported - msg: >- - differentiating enum values is not yet supported + msg: "differentiating enum values is not yet supported" - id: autodiff_stored_property_parent_not_differentiable - msg: >- - cannot differentiate access to property '%0.%1' because '%0' does not - conform to 'Differentiable' + msg: "cannot differentiate access to property '%0.%1' because '%0' does not conform to 'Differentiable'" - id: autodiff_stored_property_not_differentiable - msg: >- - cannot differentiate access to property '%0.%1' because property type %2 - does not conform to 'Differentiable' + msg: "cannot differentiate access to property '%0.%1' because property type %2 does not conform to 'Differentiable'" - id: autodiff_stored_property_tangent_not_struct - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector' is not a struct + msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector' is not a struct" - id: autodiff_stored_property_no_corresponding_tangent - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector' does not have a stored property named '%1' + msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector' does not have a stored property named '%1'" - id: autodiff_tangent_property_wrong_type - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector.%1' does not have expected type %2 + msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector.%1' does not have expected type %2" - id: autodiff_tangent_property_not_stored - msg: >- - cannot differentiate access to property '%0.%1' because - '%0.TangentVector.%1' is not a stored property + msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector.%1' is not a stored property" - id: autodiff_coroutines_not_supported - msg: >- - differentiation of coroutine calls is not yet supported + msg: "differentiation of coroutine calls is not yet supported" - id: autodiff_cannot_differentiate_writes_to_global_variables - msg: >- - cannot differentiate writes to global variables + msg: "cannot differentiate writes to global variables" - id: autodiff_cannot_differentiate_writes_to_mutable_captures - msg: >- - cannot differentiate writes to mutable captures + msg: "cannot differentiate writes to mutable captures" - id: non_physical_addressof - msg: >- - addressof only works with purely physical lvalues; use - 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing - 'withUnsafePointer' or 'withUnsafeBytes' + msg: "addressof only works with purely physical lvalues; use 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing 'withUnsafePointer' or 'withUnsafeBytes'" - id: non_borrowed_indirect_addressof - msg: >- - addressof only works with borrowable in-memory rvalues; use - 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing - 'withUnsafePointer' or 'withUnsafeBytes' + msg: "addressof only works with borrowable in-memory rvalues; use 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing 'withUnsafePointer' or 'withUnsafeBytes'" - id: opt_remark_passed - msg: >- - %0 + msg: "%0" - id: opt_remark_missed - msg: >- - %0 + msg: "%0" + +- id: opt_remark_note + msg: "%0" - id: float_to_int_overflow - msg: >- - invalid%select{| implicit}2 conversion: '%0' overflows %1 + msg: "invalid%select{| implicit}2 conversion: '%0' overflows %1" - id: negative_fp_literal_overflow_unsigned - msg: >- - negative literal '%0' cannot be converted to %select{|unsigned }2%1 + msg: "negative literal '%0' cannot be converted to %select{|unsigned }2%1" - id: warning_float_trunc_overflow - msg: >- - '%0' overflows to %select{|-}2inf during conversion to %1 + msg: "'%0' overflows to %select{|-}2inf during conversion to %1" - id: warning_float_trunc_underflow - msg: >- - '%0' underflows and loses precision during conversion to %1 + msg: "'%0' underflows and loses precision during conversion to %1" - id: warning_float_trunc_hex_inexact - msg: >- - '%0' loses precision during conversion to %1 + msg: "'%0' loses precision during conversion to %1" - id: warning_float_overflows_maxbuiltin - msg: >- - '%0' overflows to %select{|-}1inf because its magnitude exceeds the - limits of a float literal + msg: "'%0' overflows to %select{|-}1inf because its magnitude exceeds the limits of a float literal" - id: warning_int_to_fp_inexact - msg: >- - '%1' is not exactly representable as %0; it becomes '%2' + msg: "'%1' is not exactly representable as %0; it becomes '%2'" - id: return_before_yield - msg: >- - accessor must yield before returning + msg: "accessor must yield before returning" - id: multiple_yields - msg: >- - accessor must not yield more than once + msg: "accessor must not yield more than once" - id: previous_yield - msg: >- - previous yield was here + msg: "previous yield was here" - id: possible_return_before_yield - msg: >- - accessor must yield on all paths before returning + msg: "accessor must yield on all paths before returning" - id: branch_doesnt_yield - msg: >- - missing yield when the condition is %select{false|true}0 + msg: "missing yield when the condition is %select{false|true}0" - id: named_case_doesnt_yield - msg: >- - missing yield in the %0 case + msg: "missing yield in the %0 case" - id: case_doesnt_yield - msg: >- - missing yield in %select{this|the nil|the non-nil}0 case + msg: "missing yield in %select{this|the nil|the non-nil}0 case" - id: switch_value_case_doesnt_yield - msg: >- - missing yield in the %0 case + msg: "missing yield in the %0 case" - id: try_branch_doesnt_yield - msg: >- - missing yield when error is %select{not |}0thrown + msg: "missing yield when error is %select{not |}0thrown" - id: oslog_constant_eval_trap - msg: >- - %0 + msg: "%0" - id: oslog_too_many_instructions - msg: >- - interpolated expression and arguments are too complex + msg: "interpolated expression and arguments are too complex" - id: oslog_invalid_log_message - msg: >- - invalid log message; extending types defined in the os module is not - supported + msg: "invalid log message; extending types defined in the os module is not supported" - id: oslog_const_evaluable_fun_error - msg: >- - '%0' failed evaluation + msg: "'%0' failed evaluation" - id: oslog_non_constant_message - msg: >- - 'OSLogMessage' instance passed to the log call is not a constant + msg: "'OSLogMessage' instance passed to the log call is not a constant" - id: oslog_non_constant_interpolation - msg: >- - 'OSLogInterpolation' instance passed to 'OSLogMessage.init' is not a - constant + msg: "'OSLogInterpolation' instance passed to 'OSLogMessage.init' is not a constant" - id: oslog_property_not_constant - msg: >- - 'OSLogInterpolation.%0' is not a constant + msg: "'OSLogInterpolation.%0' is not a constant" - id: oslog_message_alive_after_opts - msg: >- - string interpolation cannot be used in this context; if you are calling - an os_log function, try a different overload + msg: "string interpolation cannot be used in this context; if you are calling an os_log function, try a different overload" - id: oslog_message_explicitly_created - msg: >- - 'OSLogMessage' must be created from a string interpolation or string - literal + msg: "'OSLogMessage' must be created from a string interpolation or string literal" - id: oslog_call_in_unreachable_code - msg: >- - os log call will never be executed and may have undiagnosed errors + msg: "os log call will never be executed and may have undiagnosed errors" - id: global_string_pointer_on_non_constant - msg: >- - globalStringTablePointer builtin must be used only on string literals + msg: "globalStringTablePointer builtin must be used only on string literals" - id: polymorphic_builtin_passed_non_trivial_non_builtin_type - msg: >- - Argument of type %0 can not be passed as an argument to a Polymorphic - builtin. Polymorphic builtins can only be passed arguments that are trivial - builtin typed + msg: "Argument of type %0 can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed" - id: polymorphic_builtin_passed_type_without_static_overload - msg: >- - Static overload %0 does not exist for polymorphic builtin '%1'. Static - overload implied by passing argument of type %2 + msg: "Static overload %0 does not exist for polymorphic builtin '%1'. Static overload implied by passing argument of type %2" - id: box_to_stack_cannot_promote_box_to_stack_due_to_escape_alloc - msg: >- - Can not promote value from heap to stack due to value escaping + msg: "Can not promote value from heap to stack due to value escaping" - id: box_to_stack_cannot_promote_box_to_stack_due_to_escape_location - msg: >- - value escapes here + msg: "value escapes here" - id: no_llvm_target - msg: >- - error loading LLVM target for triple '%0': %1 + msg: "error loading LLVM target for triple '%0': %1" - id: error_codegen_init_fail - msg: >- - cannot initialize code generation passes for target + msg: "cannot initialize code generation passes for target" - id: irgen_unimplemented - msg: >- - unimplemented IR generation feature %0 + msg: "unimplemented IR generation feature %0" - id: irgen_failure - msg: >- - IR generation failure: %0 + msg: "IR generation failure: %0" - id: type_to_verify_not_found - msg: >- - unable to find type '%0' to verify + msg: "unable to find type '%0' to verify" - id: type_to_verify_ambiguous - msg: >- - type to verify '%0' is ambiguous + msg: "type to verify '%0' is ambiguous" - id: type_to_verify_dependent - msg: >- - type to verify '%0' has unbound generic parameters + msg: "type to verify '%0' has unbound generic parameters" - id: too_few_output_filenames - msg: >- - too few output file names specified + msg: "too few output file names specified" - id: no_input_files_for_mt - msg: >- - no swift input files for multi-threaded compilation + msg: "no swift input files for multi-threaded compilation" - id: alignment_dynamic_type_layout_unsupported - msg: >- - @_alignment is not supported on types with dynamic layout + msg: "@_alignment is not supported on types with dynamic layout" - id: alignment_less_than_natural - msg: >- - @_alignment cannot decrease alignment below natural alignment of %0 + msg: "@_alignment cannot decrease alignment below natural alignment of %0" - id: alignment_more_than_maximum - msg: >- - @_alignment cannot increase alignment above maximum alignment of %0 + msg: "@_alignment cannot increase alignment above maximum alignment of %0" - id: warning_no_such_sdk - msg: >- - no such SDK: '%0' + msg: "no such SDK: '%0'" - id: error_no_frontend_args - msg: >- - no arguments provided to '-frontend' + msg: "no arguments provided to '-frontend'" - id: error_no_such_file_or_directory - msg: >- - no such file or directory: '%0' + msg: "no such file or directory: '%0'" - id: error_unsupported_target_os - msg: >- - unsupported target OS: '%0' + msg: "unsupported target OS: '%0'" - id: error_unsupported_target_arch - msg: >- - unsupported target architecture: '%0' + msg: "unsupported target architecture: '%0'" - id: error_unsupported_opt_for_target - msg: >- - unsupported option '%0' for target '%1' + msg: "unsupported option '%0' for target '%1'" - id: warning_inferred_simulator_target - msg: >- - inferring simulator environment for target '%0'; use '-target %1' instead + msg: "inferring simulator environment for target '%0'; use '-target %1' instead" - id: error_argument_not_allowed_with - msg: >- - argument '%0' is not allowed with '%1' + msg: "argument '%0' is not allowed with '%1'" - id: warning_argument_not_supported_with_optimization - msg: >- - argument '%0' is not supported with optimization + msg: "argument '%0' is not supported with optimization" - id: error_option_requires_sanitizer - msg: >- - option '%0' requires a sanitizer to be enabled. Use -sanitize= to enable - a sanitizer + msg: "option '%0' requires a sanitizer to be enabled. Use -sanitize= to enable a sanitizer" - id: warning_option_requires_specific_sanitizer - msg: >- - option '%0' has no effect when '%1' sanitizer is disabled. Use - -sanitize=%1 to enable the sanitizer + msg: "option '%0' has no effect when '%1' sanitizer is disabled. Use -sanitize=%1 to enable the sanitizer" - id: error_option_missing_required_argument - msg: >- - option '%0' is missing a required argument (%1) + msg: "option '%0' is missing a required argument (%1)" - id: cannot_open_file - msg: >- - cannot open file '%0' (%1) + msg: "cannot open file '%0' (%1)" - id: cannot_open_serialized_file - msg: >- - cannot open file '%0' for diagnostics emission (%1) + msg: "cannot open file '%0' for diagnostics emission (%1)" - id: error_open_input_file - msg: >- - error opening input file '%0' (%1) + msg: "error opening input file '%0' (%1)" - id: error_clang_importer_create_fail - msg: >- - clang importer creation failed + msg: "clang importer creation failed" - id: error_missing_arg_value - msg: >- - missing argument value for '%0', expected %1 argument(s) + msg: "missing argument value for '%0', expected %1 argument(s)" - id: error_unknown_arg - msg: >- - unknown argument: '%0' + msg: "unknown argument: '%0'" - id: error_invalid_arg_value - msg: >- - invalid value '%1' in '%0' + msg: "invalid value '%1' in '%0'" - id: warning_invalid_locale_code - msg: >- - unsupported locale code; supported locale codes are: '%0' + msg: "unsupported locale code; supported locale codes are: '%0'" - id: warning_locale_path_not_found - msg: >- - specified localization directory '%0' does not exist, translation is - disabled + msg: "specified localization directory '%0' does not exist, translation is disabled" - id: warning_cannot_find_locale_file - msg: >- - cannot find translations for '%0' at '%1': no such file + msg: "cannot find translations for '%0' at '%1': no such file" - id: warning_cannot_multithread_batch_mode - msg: >- - ignoring -num-threads argument; cannot multithread batch mode + msg: "ignoring -num-threads argument; cannot multithread batch mode" - id: error_unsupported_option_argument - msg: >- - unsupported argument '%1' to option '%0' + msg: "unsupported argument '%1' to option '%0'" - id: error_immediate_mode_missing_stdlib - msg: >- - could not load the swift standard library + msg: "could not load the swift standard library" - id: error_immediate_mode_missing_library - msg: >- - could not load %select{shared library|framework}0 '%1' + msg: "could not load %select{shared library|framework}0 '%1'" - id: error_immediate_mode_primary_file - msg: >- - immediate mode is incompatible with -primary-file + msg: "immediate mode is incompatible with -primary-file" - id: error_missing_frontend_action - msg: >- - no frontend action was selected + msg: "no frontend action was selected" - id: error_invalid_source_location_str - msg: >- - invalid source location string '%0' + msg: "invalid source location string '%0'" - id: error_no_source_location_scope_map - msg: >- - -dump-scope-maps argument must be 'expanded' or a list of source - locations + msg: "-dump-scope-maps argument must be 'expanded' or a list of source locations" - id: note_valid_swift_versions - msg: >- - valid arguments to '-swift-version' are %0 + msg: "valid arguments to '-swift-version' are %0" - id: error_mode_cannot_emit_dependencies - msg: >- - this mode does not support emitting dependency files + msg: "this mode does not support emitting dependency files" - id: error_mode_cannot_emit_reference_dependencies - msg: >- - this mode does not support emitting reference dependency files + msg: "this mode does not support emitting reference dependency files" - id: error_mode_cannot_emit_swift_ranges - msg: >- - this mode does not support emitting unparsed ranges files + msg: "this mode does not support emitting unparsed ranges files" - id: error_mode_cannot_emit_compiled_source - msg: >- - this mode does not support emitting compiled source files + msg: "this mode does not support emitting compiled source files" - id: error_mode_cannot_emit_header - msg: >- - this mode does not support emitting Objective-C headers + msg: "this mode does not support emitting Objective-C headers" - id: error_mode_cannot_emit_loaded_module_trace - msg: >- - this mode does not support emitting the loaded module trace + msg: "this mode does not support emitting the loaded module trace" - id: error_mode_cannot_emit_module - msg: >- - this mode does not support emitting modules + msg: "this mode does not support emitting modules" - id: error_mode_cannot_emit_module_doc - msg: >- - this mode does not support emitting module documentation files + msg: "this mode does not support emitting module documentation files" - id: error_mode_cannot_emit_module_source_info - msg: >- - this mode does not support emitting module source info files + msg: "this mode does not support emitting module source info files" - id: error_mode_cannot_emit_interface - msg: >- - this mode does not support emitting module interface files + msg: "this mode does not support emitting module interface files" - id: cannot_emit_ir_skipping_function_bodies - msg: >- - -experimental-skip-non-inlinable-function-bodies does not support - emitting IR + msg: "-experimental-skip-non-inlinable-function-bodies does not support emitting IR" - id: emit_reference_dependencies_without_primary_file - msg: >- - ignoring -emit-reference-dependencies (requires -primary-file) + msg: "ignoring -emit-reference-dependencies (requires -primary-file)" - id: emit_swift_ranges_without_primary_file - msg: >- - ignoring -emit-swift-ranges (requires -primary-file) + msg: "ignoring -emit-swift-ranges (requires -primary-file)" - id: emit_compiled_source_without_primary_file - msg: >- - ignoring -emit-compiled-source (requires -primary-file) + msg: "ignoring -emit-compiled-source (requires -primary-file)" - id: error_bad_module_name - msg: >- - module name "%0" is not a valid identifier%select{|; use -module-name - flag to specify an alternate name}1 + msg: "module name \"%0\" is not a valid identifier%select{|; use -module-name flag to specify an alternate name}1" - id: error_stdlib_module_name - msg: >- - module name "%0" is reserved for the standard library%select{|; use - -module-name flag to specify an alternate name}1 + msg: "module name \"%0\" is reserved for the standard library%select{|; use -module-name flag to specify an alternate name}1" - id: error_stdlib_not_found - msg: >- - unable to load standard library for target '%0' + msg: "unable to load standard library for target '%0'" - id: error_unable_to_load_supplementary_output_file_map - msg: >- - unable to load supplementary output file map '%0': %1 + msg: "unable to load supplementary output file map '%0': %1" - id: error_missing_entry_in_supplementary_output_file_map - msg: >- - supplementary output file map '%0' is missing an entry for '%1' (this - likely indicates a compiler issue; please file a bug report) + msg: "supplementary output file map '%0' is missing an entry for '%1' (this likely indicates a compiler issue; please file a bug report)" - id: error_repl_requires_no_input_files - msg: >- - REPL mode requires no input files + msg: "REPL mode requires no input files" - id: error_mode_requires_one_input_file - msg: >- - this mode requires a single input file + msg: "this mode requires a single input file" - id: error_mode_requires_an_input_file - msg: >- - this mode requires at least one input file + msg: "this mode requires at least one input file" - id: error_mode_requires_one_sil_multi_sib - msg: >- - this mode requires .sil for primary-file and only .sib for other inputs + msg: "this mode requires .sil for primary-file and only .sib for other inputs" - id: error_no_output_filename_specified - msg: >- - an output filename was not specified for a mode which requires an output - filename + msg: "an output filename was not specified for a mode which requires an output filename" - id: error_implicit_output_file_is_directory - msg: >- - the implicit output file '%0' is a directory; explicitly specify a - filename using -o + msg: "the implicit output file '%0' is a directory; explicitly specify a filename using -o" - id: error_if_any_output_files_are_specified_they_all_must_be - msg: >- - if any output files are specified, they all must be + msg: "if any output files are specified, they all must be" - id: error_primary_file_not_found - msg: >- - primary file '%0' was not found in file list '%1' + msg: "primary file '%0' was not found in file list '%1'" - id: error_cannot_have_input_files_with_file_list - msg: >- - cannot have input files with file list + msg: "cannot have input files with file list" - id: error_cannot_have_primary_files_with_primary_file_list - msg: >- - cannot have primary input files with primary file list + msg: "cannot have primary input files with primary file list" - id: error_cannot_have_supplementary_outputs - msg: >- - cannot have '%0' with '%1' + msg: "cannot have '%0' with '%1'" - id: error_duplicate_input_file - msg: >- - duplicate input file '%0' + msg: "duplicate input file '%0'" - id: repl_must_be_initialized - msg: >- - variables currently must have an initial value when entered at the top - level of the REPL + msg: "variables currently must have an initial value when entered at the top level of the REPL" - id: verify_encountered_fatal - msg: >- - fatal error encountered while in -verify mode + msg: "fatal error encountered while in -verify mode" - id: error_parse_input_file - msg: >- - error parsing input file '%0' (%1) + msg: "error parsing input file '%0' (%1)" - id: error_write_index_unit - msg: >- - writing index unit file: %0 + msg: "writing index unit file: %0" - id: error_create_index_dir - msg: >- - creating index directory: %0 + msg: "creating index directory: %0" - id: error_write_index_record - msg: >- - writing index record file: %0 + msg: "writing index record file: %0" - id: error_index_failed_status_check - msg: >- - failed file status check: %0 + msg: "failed file status check: %0" - id: error_index_inputs_more_than_outputs - msg: >- - index output filenames do not match input source files + msg: "index output filenames do not match input source files" - id: error_wrong_number_of_arguments - msg: >- - wrong number of '%0' arguments (expected %1, got %2) + msg: "wrong number of '%0' arguments (expected %1, got %2)" - id: error_formatting_multiple_file_ranges - msg: >- - file ranges don't support multiple input files + msg: "file ranges don't support multiple input files" - id: error_formatting_invalid_range - msg: >- - file range is invalid + msg: "file range is invalid" - id: stats_disabled - msg: >- - compiler was not built with support for collecting statistics + msg: "compiler was not built with support for collecting statistics" - id: tbd_warn_truncating_version - msg: >- - truncating %select{current|compatibility}0 version '%1' in TBD file to - fit in 32-bit space used by old mach-o format + msg: "truncating %select{current|compatibility}0 version '%1' in TBD file to fit in 32-bit space used by old mach-o format" - id: tbd_err_invalid_version - msg: >- - invalid dynamic library %select{current|compatibility}0 version '%1' + msg: "invalid dynamic library %select{current|compatibility}0 version '%1'" - id: tbd_only_supported_in_whole_module - msg: >- - TBD generation is only supported when the whole module can be seen + msg: "TBD generation is only supported when the whole module can be seen" - id: tbd_not_supported_with_cmo - msg: >- - Test-Based InstallAPI (TBD) is not support with cross-module-optimization + msg: "Test-Based InstallAPI (TBD) is not support with cross-module-optimization" - id: linker_directives_choice_confusion - msg: >- - only one of -emit-ldadd-cfile-path and -module-installname-map-file can - be specified;the c file won't be generated + msg: "only one of -emit-ldadd-cfile-path and -module-installname-map-file can be specified;the c file won't be generated" - id: previous_installname_map_missing - msg: >- - cannot open previous install name map from %0 + msg: "cannot open previous install name map from %0" - id: previous_installname_map_corrupted - msg: >- - previous install name map from %0 is malformed + msg: "previous install name map from %0 is malformed" - id: explicit_swift_module_map_missing - msg: >- - cannot open explicit Swift module map from %0 + msg: "cannot open explicit Swift module map from %0" - id: explicit_swift_module_map_corrupted - msg: >- - explicit Swift module map from %0 is malformed + msg: "explicit Swift module map from %0 is malformed" + +- id: placeholder_dependency_module_map_missing + msg: "cannot open Swift placeholder dependency module map from %0" + +- id: placeholder_dependency_module_map_corrupted + msg: "Swift placeholder dependency module map from %0 is malformed" - id: default_previous_install_name - msg: >- - default previous install name for %0 is %1 + msg: "default previous install name for %0 is %1" - id: platform_previous_install_name - msg: >- - previous install name for %0 in %1 is %2 + msg: "previous install name for %0 in %1 is %2" - id: unknown_platform_name - msg: >- - unkown platform name %0 + msg: "unkown platform name %0" - id: unknown_swift_module_name - msg: >- - cannot find Swift module with name %0 + msg: "cannot find Swift module with name %0" - id: cannot_find_install_name - msg: >- - cannot find previous install name for module %0 in %1 + msg: "cannot find previous install name for module %0 in %1" - id: symbol_in_tbd_not_in_ir - msg: >- - symbol '%0' (%1) is in TBD file, but not in generated IR + msg: "symbol '%0' (%1) is in TBD file, but not in generated IR" - id: symbol_in_ir_not_in_tbd - msg: >- - symbol '%0' (%1) is in generated IR file, but not in TBD file + msg: "symbol '%0' (%1) is in generated IR file, but not in TBD file" - id: tbd_validation_failure - msg: >- - please file a radar or open a bug on bugs.swift.org with this code, and - add -Xfrontend -validate-tbd-against-ir=none to squash the errors + msg: "please file a radar or open a bug on bugs.swift.org with this code, and add -Xfrontend -validate-tbd-against-ir=none to squash the errors" - id: redundant_prefix_compilation_flag - msg: >- - invalid argument '-D%0'; did you provide a redundant '-D' in your build - settings? + msg: "invalid argument '-D%0'; did you provide a redundant '-D' in your build settings?" - id: invalid_conditional_compilation_flag - msg: >- - conditional compilation flags must be valid Swift identifiers (rather - than '%0') + msg: "conditional compilation flags must be valid Swift identifiers (rather than '%0')" - id: cannot_assign_value_to_conditional_compilation_flag - msg: >- - conditional compilation flags do not have values in Swift; they are - either present or absent (rather than '%0') + msg: "conditional compilation flags do not have values in Swift; they are either present or absent (rather than '%0')" - id: framework_search_path_includes_framework_extension - msg: >- - framework search path ends in ".framework"; add directory containing - framework instead: %0 + msg: "framework search path ends in \".framework\"; add directory containing framework instead: %0" - id: error_optimization_remark_pattern - msg: >- - %0 in '%1' + msg: "%0 in '%1'" - id: error_invalid_debug_prefix_map - msg: >- - invalid argument '%0' to -debug-prefix-map; it must be of the form - 'original=remapped' + msg: "invalid argument '%0' to -debug-prefix-map; it must be of the form 'original=remapped'" - id: error_invalid_coverage_prefix_map - msg: >- - invalid argument '%0' to -coverage-prefix-map; it must be of the form - 'original=remapped' + msg: "invalid argument '%0' to -coverage-prefix-map; it must be of the form 'original=remapped'" - id: error_unable_to_write_swift_ranges_file - msg: >- - unable to write unparsed ranges file '$0': %1 + msg: "unable to write unparsed ranges file '$0': %1" - id: error_unable_to_write_compiled_source_file - msg: >- - unable to write compiled source file: '$0': %1 + msg: "unable to write compiled source file: '$0': %1" - id: invalid_vfs_overlay_file - msg: >- - invalid virtual overlay file '%0' + msg: "invalid virtual overlay file '%0'" - id: module_interface_scoped_import_unsupported - msg: >- - scoped imports are not yet supported in module interfaces + msg: "scoped imports are not yet supported in module interfaces" - id: warn_unsupported_module_interface_swift_version - msg: >- - module interfaces are only supported with Swift language version 5 or - later (currently using -swift-version %0) + msg: "module interfaces are only supported with Swift language version 5 or later (currently using -swift-version %0)" - id: warn_unsupported_module_interface_library_evolution - msg: >- - module interfaces are only supported with -enable-library-evolution + msg: "module interfaces are only supported with -enable-library-evolution" - id: error_extracting_version_from_module_interface - msg: >- - error extracting version from module interface + msg: "error extracting version from module interface" - id: unsupported_version_of_module_interface - msg: >- - unsupported version of module interface '%0': '%1' + msg: "unsupported version of module interface '%0': '%1'" - id: error_opening_explicit_module_file - msg: >- - failed to open explicit Swift module: %0 + msg: "failed to open explicit Swift module: %0" - id: error_extracting_flags_from_module_interface - msg: >- - error extracting flags from module interface + msg: "error extracting flags from module interface" - id: rebuilding_module_from_interface - msg: >- - rebuilding module '%0' from interface '%1' + msg: "rebuilding module '%0' from interface '%1'" - id: out_of_date_module_here - msg: >- - %select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1' + msg: "%select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1'" - id: module_interface_dependency_out_of_date - msg: >- - dependency is out of date: '%0' + msg: "dependency is out of date: '%0'" - id: module_interface_dependency_missing - msg: >- - dependency is missing: '%0' + msg: "dependency is missing: '%0'" - id: compiled_module_invalid - msg: >- - unable to load compiled module '%0' + msg: "unable to load compiled module '%0'" - id: compiled_module_invalid_reason - msg: >- - unable to load compiled module '%0': %1 + msg: "unable to load compiled module '%0': %1" - id: unknown_forced_module_loading_mode - msg: >- - unknown value for SWIFT_FORCE_MODULE_LOADING variable: '%0' + msg: "unknown value for SWIFT_FORCE_MODULE_LOADING variable: '%0'" - id: error_creating_remark_serializer - msg: >- - error while creating remark serializer: '%0' + msg: "error while creating remark serializer: '%0'" - id: interface_file_lock_failure - msg: >- - could not acquire lock file for module interface '%0' + msg: "could not acquire lock file for module interface '%0'" - id: interface_file_lock_timed_out - msg: >- - timed out waiting to acquire lock file for module interface '%0' + msg: "timed out waiting to acquire lock file for module interface '%0'" - id: dependency_cascading_mismatch - msg: >- - expected %select{non-cascading|cascading}0 dependency; found - %select{non-cascading|cascading}1 dependency instead + msg: "expected %select{non-cascading|cascading}0 dependency; found %select{non-cascading|cascading}1 dependency instead" - id: potential_dependency_cascading_mismatch - msg: >- - expected %select{non-cascading|cascading}0 potential member dependency; - found %select{non-cascading|cascading}1 potential member dependency instead + msg: "expected %select{non-cascading|cascading}0 potential member dependency; found %select{non-cascading|cascading}1 potential member dependency instead" - id: missing_member_dependency - msg: >- - expected %select{%error|provided|member|potential member|dynamic member}0 - dependency does not exist: %1 + msg: "expected %select{%error|provided|member|potential member|dynamic member}0 dependency does not exist: %1" - id: unexpected_dependency - msg: >- - unexpected %0 %select{%error|%error|member|potential member|dynamic - member}1 dependency: %2 + msg: "unexpected %0 %select{%error|%error|member|potential member|dynamic member}1 dependency: %2" - id: unexpected_provided_entity - msg: >- - unexpected provided entity: %0 + msg: "unexpected provided entity: %0" - id: negative_expectation_violated - msg: >- - unexpected dependency exists: %0 + msg: "unexpected dependency exists: %0" - id: expectation_missing_opening_braces - msg: >- - expected {{ in expectation + msg: "expected {{ in expectation" - id: expectation_missing_closing_braces - msg: >- - didn't find '}}' to match '{{' in expectation + msg: "didn't find '}}' to match '{{' in expectation" - id: module_incompatible_with_skip_function_bodies - msg: >- - module '%0' cannot be built with - -experimental-skip-non-inlinable-function-bodies; this option has been - automatically disabled + msg: "module '%0' cannot be built with -experimental-skip-non-inlinable-function-bodies; this option has been automatically disabled" - id: warning_parallel_execution_not_supported - msg: >- - parallel execution not supported; falling back to serial execution + msg: "parallel execution not supported; falling back to serial execution" - id: error_unable_to_execute_command - msg: >- - unable to execute command: %0 + msg: "unable to execute command: %0" - id: error_command_signalled_without_signal_number - msg: >- - %0 command failed due to signal (use -v to see invocation) + msg: "%0 command failed due to signal (use -v to see invocation)" - id: error_command_signalled - msg: >- - %0 command failed due to signal %1 (use -v to see invocation) + msg: "%0 command failed due to signal %1 (use -v to see invocation)" - id: error_command_failed - msg: >- - %0 command failed with exit code %1 (use -v to see invocation) + msg: "%0 command failed with exit code %1 (use -v to see invocation)" - id: error_expected_one_frontend_job - msg: >- - unable to handle compilation, expected exactly one frontend job + msg: "unable to handle compilation, expected exactly one frontend job" - id: error_expected_frontend_command - msg: >- - expected a swift frontend command + msg: "expected a swift frontend command" - id: error_cannot_specify__o_for_multiple_outputs - msg: >- - cannot specify -o when generating multiple output files + msg: "cannot specify -o when generating multiple output files" - id: error_static_emit_executable_disallowed - msg: >- - -static may not be used with -emit-executable + msg: "-static may not be used with -emit-executable" - id: error_unable_to_load_output_file_map - msg: >- - unable to load output file map '%1': %0 + msg: "unable to load output file map '%1': %0" - id: error_no_output_file_map_specified - msg: >- - no output file map specified + msg: "no output file map specified" - id: error_unable_to_make_temporary_file - msg: >- - unable to make temporary file: %0 + msg: "unable to make temporary file: %0" - id: error_no_input_files - msg: >- - no input files + msg: "no input files" - id: error_unexpected_input_file - msg: >- - unexpected input file: %0 + msg: "unexpected input file: %0" - id: error_unknown_target - msg: >- - unknown target '%0' + msg: "unknown target '%0'" - id: error_framework_bridging_header - msg: >- - using bridging headers with framework targets is unsupported + msg: "using bridging headers with framework targets is unsupported" - id: error_bridging_header_module_interface - msg: >- - using bridging headers with module interfaces is unsupported + msg: "using bridging headers with module interfaces is unsupported" - id: error_i_mode - msg: >- - the flag '-i' is no longer required and has been removed; use '%0 - input-filename' + msg: "the flag '-i' is no longer required and has been removed; use '%0 input-filename'" - id: warning_unnecessary_repl_mode - msg: >- - unnecessary option '%0'; this is the default for '%1' with no input files + msg: "unnecessary option '%0'; this is the default for '%1' with no input files" - id: error_unsupported_option - msg: >- - option '%0' is not supported by '%1'; did you mean to use '%2'? + msg: "option '%0' is not supported by '%1'; did you mean to use '%2'?" - id: incremental_requires_output_file_map - msg: >- - ignoring -incremental (currently requires an output file map) + msg: "ignoring -incremental (currently requires an output file map)" - id: incremental_requires_build_record_entry - msg: >- - ignoring -incremental; output file map has no master dependencies entry - ("%0" under "") + msg: "ignoring -incremental; output file map has no master dependencies entry (\"%0\" under \"\")" - id: unable_to_open_incremental_comparison_log - msg: >- - unable to open incremental comparison log file '%0' + msg: "unable to open incremental comparison log file '%0'" - id: error_os_minimum_deployment - msg: >- - Swift requires a minimum deployment target of %0 + msg: "Swift requires a minimum deployment target of %0" - id: error_sdk_too_old - msg: >- - Swift does not support the SDK '%0' + msg: "Swift does not support the SDK '%0'" - id: error_ios_maximum_deployment_32 - msg: >- - iOS %0 does not support 32-bit programs + msg: "iOS %0 does not support 32-bit programs" - id: error_unsupported_target_variant - msg: >- - unsupported '%select{-target|-target-variant}1' value '%0'; use - 'ios-macabi' instead + msg: "unsupported '%select{-target|-target-variant}1' value '%0'; use 'ios-macabi' instead" - id: warn_arclite_not_found_when_link_objc_runtime - msg: >- - unable to find Objective-C runtime support library 'arclite'; pass - '-no-link-objc-runtime' to silence this warning - -- id: error_two_files_same_name - msg: >- - filename "%0" used twice: '%1' and '%2' - -- id: note_explain_two_files_same_name - msg: >- - filenames are used to distinguish private declarations with the same name + msg: "unable to find Objective-C runtime support library 'arclite'; pass '-no-link-objc-runtime' to silence this warning" - id: warn_cannot_stat_input - msg: >- - unable to determine when '%0' was last modified: %1 + msg: "unable to determine when '%0' was last modified: %1" - id: warn_unable_to_load_dependencies - msg: >- - unable to load dependencies file "%0", disabling incremental mode + msg: "unable to load dependencies file \"%0\", disabling incremental mode" - id: error_input_changed_during_build - msg: >- - input file '%0' was modified during the build + msg: "input file '%0' was modified during the build" - id: error_conflicting_options - msg: >- - conflicting options '%0' and '%1' + msg: "conflicting options '%0' and '%1'" - id: error_option_not_supported - msg: >- - '%0' is not supported with '%1' + msg: "'%0' is not supported with '%1'" + +- id: error_requirement_not_met + msg: "'%0' requires '%1'" - id: warn_ignore_embed_bitcode - msg: >- - ignoring -embed-bitcode since no object file is being generated + msg: "ignoring -embed-bitcode since no object file is being generated" - id: warn_ignore_embed_bitcode_marker - msg: >- - ignoring -embed-bitcode-marker since no object file is being generated + msg: "ignoring -embed-bitcode-marker since no object file is being generated" - id: verify_debug_info_requires_debug_option - msg: >- - ignoring '-verify-debug-info'; no debug info is being generated + msg: "ignoring '-verify-debug-info'; no debug info is being generated" - id: verify_incremental_dependencies_needs_incremental - msg: >- - '-verify-incremental-dependencies' requires '-incremental' + msg: "'-verify-incremental-dependencies' requires '-incremental'" - id: error_profile_missing - msg: >- - no profdata file exists at '%0' + msg: "no profdata file exists at '%0'" - id: warn_opt_remark_disabled - msg: >- - Emission of optimization records has been disabled, because it requires a - single compiler invocation: consider enabling the -whole-module-optimization - flag + msg: "Emission of optimization records has been disabled, because it requires a single compiler invocation: consider enabling the -whole-module-optimization flag" - id: warn_ignoring_batch_mode - msg: >- - ignoring '-enable-batch-mode' because '%0' was also specified + msg: "ignoring '-enable-batch-mode' because '%0' was also specified" - id: warn_ignoring_wmo - msg: >- - ignoring '-wmo' because '-dump-ast' was also specified + msg: "ignoring '-wmo' because '-dump-ast' was also specified" - id: warn_ignoring_source_range_dependencies - msg: >- - ignoring '-enable-source-range-dependencies' because '%0' was also specified + msg: "ignoring '-enable-source-range-dependencies' because '%0' was also specified" - id: warn_bad_swift_ranges_header - msg: >- - ignoring '-enable-source-range-dependencies' because of bad header in '%0' + msg: "ignoring '-enable-source-range-dependencies' because of bad header in '%0'" - id: warn_bad_swift_ranges_format - msg: >- - ignoring '-enable-source-range-dependencies' because of bad format '%1' - in '%0' + msg: "ignoring '-enable-source-range-dependencies' because of bad format '%1' in '%0'" - id: warn_use_filelists_deprecated - msg: >- - the option '-driver-use-filelists' is deprecated; use - '-driver-filelist-threshold=0' instead + msg: "the option '-driver-use-filelists' is deprecated; use '-driver-filelist-threshold=0' instead" - id: warn_unable_to_load_swift_ranges - msg: >- - unable to load swift ranges file "%0", %1 + msg: "unable to load swift ranges file \"%0\", %1" - id: warn_unable_to_load_compiled_swift - msg: >- - unable to load previously compiled swift file "%0", %1 + msg: "unable to load previously compiled swift file \"%0\", %1" - id: warn_unable_to_load_primary - msg: >- - unable to load primary swift file "%0", %1 + msg: "unable to load primary swift file \"%0\", %1" - id: cannot_find_migration_script - msg: >- - missing migration script from path '%0' + msg: "missing migration script from path '%0'" - id: error_darwin_static_stdlib_not_supported - msg: >- - -static-stdlib is no longer supported on Apple platforms + msg: "-static-stdlib is no longer supported on Apple platforms" + +- id: error_darwin_only_supports_libcxx + msg: "The only C++ standard library supported on Apple platforms is libc++" - id: warn_drv_darwin_sdk_invalid_settings - msg: >- - SDK settings were ignored because 'SDKSettings.json' could not be parsed + msg: "SDK settings were ignored because 'SDKSettings.json' could not be parsed" - id: invalid_name - msg: >- - '%0' is not a valid name + msg: "'%0' is not a valid name" - id: invalid_location - msg: >- - given location is not valid + msg: "given location is not valid" - id: arity_mismatch - msg: >- - the given new name '%0' does not match the arity of the old name '%1' + msg: "the given new name '%0' does not match the arity of the old name '%1'" - id: name_not_functionlike - msg: >- - the 'call' name usage cannot be used with a non-function-like name '%0' + msg: "the 'call' name usage cannot be used with a non-function-like name '%0'" - id: unresolved_location - msg: >- - cannot resolve location as name + msg: "cannot resolve location as name" - id: location_module_mismatch - msg: >- - given location does not belong to module '%0' + msg: "given location does not belong to module '%0'" - id: value_decl_no_loc - msg: >- - value decl '%0' has no declaration location + msg: "value decl '%0' has no declaration location" - id: value_decl_referenced_out_of_range - msg: >- - value decl '%0' is referenced out of range + msg: "value decl '%0' is referenced out of range" - id: multi_entry_range - msg: >- - selected range has more than one entry point + msg: "selected range has more than one entry point" - id: orphan_loop_keyword - msg: >- - selected range contains %0 but not its target loop + msg: "selected range contains %0 but not its target loop" - id: invalid_default_location - msg: >- - given location is not on a default statement + msg: "given location is not on a default statement" - id: no_parent_switch - msg: >- - cannot find enclosing switch statement + msg: "cannot find enclosing switch statement" - id: no_remaining_cases - msg: >- - no remaining cases to expand + msg: "no remaining cases to expand" - id: mismatched_rename - msg: >- - the name at the given location cannot be renamed to '%0' + msg: "the name at the given location cannot be renamed to '%0'" - id: no_insert_position - msg: >- - cannot find inserting position + msg: "cannot find inserting position" - id: generic_sig_change - msg: >- - %0 has generic signature change from %1 to %2 + msg: "%0 has generic signature change from %1 to %2" - id: raw_type_change - msg: >- - %0(%1) is now %2 representable + msg: "%0(%1) is now %2 representable" - id: removed_decl - msg: >- - %0 has been removed%select{| (deprecated)}1 + msg: "%0 has been removed%select{| (deprecated)}1" - id: moved_decl - msg: >- - %0 has been moved to %1 + msg: "%0 has been moved to %1" - id: renamed_decl - msg: >- - %0 has been renamed to %1 + msg: "%0 has been renamed to %1" - id: decl_type_change - msg: >- - %0 has %1 type change from %2 to %3 + msg: "%0 has %1 type change from %2 to %3" - id: decl_attr_change - msg: >- - %0 changes from %1 to %2 + msg: "%0 changes from %1 to %2" - id: decl_new_attr - msg: >- - %0 is now %1 + msg: "%0 is now %1" - id: decl_reorder - msg: >- - %0 in a non-resilient type changes position from %1 to %2 + msg: "%0 in a non-resilient type changes position from %1 to %2" - id: decl_added - msg: >- - %0 is added to a non-resilient type + msg: "%0 is added to a non-resilient type" - id: var_has_fixed_order_change - msg: >- - %0 is %select{now|no longer}1 a stored property + msg: "%0 is %select{now|no longer}1 a stored property" - id: func_has_fixed_order_change - msg: >- - %0 is %select{now|no longer}1 a non-final instance function + msg: "%0 is %select{now|no longer}1 a non-final instance function" - id: default_arg_removed - msg: >- - %0 has removed default argument from %1 + msg: "%0 has removed default argument from %1" - id: conformance_removed - msg: >- - %0 has removed %select{conformance to|inherited protocol}2 %1 + msg: "%0 has removed %select{conformance to|inherited protocol}2 %1" - id: conformance_added - msg: >- - %0 has added inherited protocol %1 + msg: "%0 has added inherited protocol %1" - id: existing_conformance_added - msg: >- - %0 has added a conformance to an existing protocol %1 + msg: "%0 has added a conformance to an existing protocol %1" - id: default_associated_type_removed - msg: >- - %0 has removed default type %1 + msg: "%0 has removed default type %1" - id: protocol_req_added - msg: >- - %0 has been added as a protocol requirement + msg: "%0 has been added as a protocol requirement" - id: super_class_removed - msg: >- - %0 has removed its super class %1 + msg: "%0 has removed its super class %1" - id: super_class_changed - msg: >- - %0 has changed its super class from %1 to %2 + msg: "%0 has changed its super class from %1 to %2" - id: decl_kind_changed - msg: >- - %0 has been changed to a %1 + msg: "%0 has been changed to a %1" - id: optional_req_changed - msg: >- - %0 is %select{now|no longer}1 an optional requirement + msg: "%0 is %select{now|no longer}1 an optional requirement" - id: no_longer_open - msg: >- - %0 is no longer open for subclassing + msg: "%0 is no longer open for subclassing" - id: func_type_escaping_changed - msg: >- - %0 has %select{removed|added}2 @escaping in %1 + msg: "%0 has %select{removed|added}2 @escaping in %1" - id: func_self_access_change - msg: >- - %0 has self access kind changing from %1 to %2 + msg: "%0 has self access kind changing from %1 to %2" - id: param_ownership_change - msg: >- - %0 has %1 changing from %2 to %3 + msg: "%0 has %1 changing from %2 to %3" - id: type_witness_change - msg: >- - %0 has type witness type for %1 changing from %2 to %3 + msg: "%0 has type witness type for %1 changing from %2 to %3" - id: decl_new_witness_table_entry - msg: >- - %0 now requires %select{|no}1 new witness table entry + msg: "%0 now requires %select{|no}1 new witness table entry" - id: new_decl_without_intro - msg: >- - %0 is a new API without @available attribute + msg: "%0 is a new API without @available attribute" - id: objc_name_change - msg: >- - %0 has ObjC name change from %1 to %2 + msg: "%0 has ObjC name change from %1 to %2" - id: desig_init_added - msg: >- - %0 has been added as a designated initializer to an open class + msg: "%0 has been added as a designated initializer to an open class" - id: added_invisible_designated_init - msg: >- - %0 has new designated initializers that are not visible to clients + msg: "%0 has new designated initializers that are not visible to clients" - id: not_inheriting_convenience_inits - msg: >- - %0 no longer inherits convenience inits from its superclass + msg: "%0 no longer inherits convenience inits from its superclass" - id: enum_case_added - msg: >- - %0 has been added as a new enum case - + msg: "%0 has been added as a new enum case" From 9331cfab870c1df29a18915e174e2aec97991e18 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 13 Aug 2020 14:25:44 -0700 Subject: [PATCH 126/663] [Concurrency] Fix one last test for __await -> await --- test/Syntax/Parser/async.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Syntax/Parser/async.swift b/test/Syntax/Parser/async.swift index c04b6f9f956e7..686491170eb4d 100644 --- a/test/Syntax/Parser/async.swift +++ b/test/Syntax/Parser/async.swift @@ -16,7 +16,7 @@ func testTypeExprs() { } func testAwaitOperator() async { - let _ = __await asyncGlobal1() + let _ = await asyncGlobal1() } func testAsyncClosure() { From 2cfb5fa32653b5c994a5dacea8253b897a414a63 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 13 Aug 2020 13:12:32 -0700 Subject: [PATCH 127/663] [ConstraintLocator] Simplify ConstraintLocator::Profile. Since each kind of path element stores only one type of data, the path element kind and the raw storage value are sufficient for uniquing the element. --- lib/Sema/ConstraintLocator.cpp | 49 +--------------------------------- lib/Sema/ConstraintLocator.h | 5 ++-- 2 files changed, 4 insertions(+), 50 deletions(-) diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index d570c8983b13e..c5b4a864e4e05 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -32,54 +32,7 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, ASTNode anchor, id.AddInteger(path.size()); for (auto elt : path) { id.AddInteger(elt.getKind()); - switch (elt.getKind()) { - case GenericParameter: - id.AddPointer(elt.castTo().getType()); - break; - - case ProtocolRequirement: { - auto reqElt = elt.castTo(); - id.AddPointer(reqElt.getDecl()); - break; - } - - case Witness: - id.AddPointer(elt.castTo().getDecl()); - break; - - case KeyPathDynamicMember: { - auto kpElt = elt.castTo(); - id.AddPointer(kpElt.getKeyPathDecl()); - break; - } - - case PatternMatch: - id.AddPointer(elt.castTo().getPattern()); - break; - - case ArgumentAttribute: - case GenericArgument: - case NamedTupleElement: - case TupleElement: - case ApplyArgToParam: - case OpenedGeneric: - case KeyPathComponent: - case ConditionalRequirement: - case TypeParameterRequirement: - case ContextualType: - case SynthesizedArgument: - case TernaryBranch: - case ClosureBody: { - auto numValues = numNumericValuesInPathElement(elt.getKind()); - for (unsigned i = 0; i < numValues; ++i) - id.AddInteger(elt.getValue(i)); - break; - } -#define SIMPLE_LOCATOR_PATH_ELT(Name) case Name : -#include "ConstraintLocatorPathElts.def" - // Nothing to do for simple locator elements. - break; - } + id.AddInteger(elt.getRawStorage()); } } diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 85bb04eeff927..8316271de4b7a 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -201,8 +201,6 @@ class ConstraintLocator : public llvm::FoldingSetNode { return reinterpret_cast(storage << 3); } - friend class ConstraintLocator; - public: #define LOCATOR_PATH_ELT(Name) class Name; #include "ConstraintLocatorPathElts.def" @@ -217,6 +215,9 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// Retrieve the kind of path element. PathElementKind getKind() const { return kind; } + /// Retrieve the raw storage value. + uint64_t getRawStorage() const { return storage; } + /// Attempts to cast the path element to a specific \c LocatorPathElt /// subclass, returning \c None if unsuccessful. template From 7378afd1bf3d5b0324e99420d5632ce7e8e30a32 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Thu, 13 Aug 2020 15:25:20 -0700 Subject: [PATCH 128/663] Pass -isysroot to both CFLAGS and LDFLAGS when building ninja (#33414) * Pass -isysroot to both CFLAGS and LDFLAGS when building ninja * Update test expectations too --- .../swift_build_support/swift_build_support/products/ninja.py | 4 ++-- utils/swift_build_support/tests/products/test_ninja.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/swift_build_support/swift_build_support/products/ninja.py b/utils/swift_build_support/swift_build_support/products/ninja.py index 53ebb15c6e32e..d133c22fa9ded 100644 --- a/utils/swift_build_support/swift_build_support/products/ninja.py +++ b/utils/swift_build_support/swift_build_support/products/ninja.py @@ -63,8 +63,8 @@ def build(self): "-isysroot {sysroot} -mmacosx-version-min={osx_version}" ).format(sysroot=sysroot, osx_version=osx_version_min), "LDFLAGS": ( - "-mmacosx-version-min={osx_version}" - ).format(osx_version=osx_version_min), + "-isysroot {sysroot} -mmacosx-version-min={osx_version}" + ).format(sysroot=sysroot, osx_version=osx_version_min), } elif self.toolchain.cxx: env = { diff --git a/utils/swift_build_support/tests/products/test_ninja.py b/utils/swift_build_support/tests/products/test_ninja.py index 5a3c919732d11..3eb26c4a838a0 100644 --- a/utils/swift_build_support/tests/products/test_ninja.py +++ b/utils/swift_build_support/tests/products/test_ninja.py @@ -101,7 +101,7 @@ def test_build(self): "env " "'CFLAGS=-isysroot {sysroot} -mmacosx-version-min=10.9' " "CXX={cxx} " - "LDFLAGS=-mmacosx-version-min=10.9 " + "'LDFLAGS=-isysroot {sysroot} -mmacosx-version-min=10.9' " ).format( cxx=self.toolchain.cxx, sysroot=xcrun.sdk_path('macosx') From e2e69578a69ede859f900a55d8b9d334fcc07fd7 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Thu, 13 Aug 2020 15:26:04 -0700 Subject: [PATCH 129/663] For the 'minimal' stdlib, disable Objective-C interop (#33427) --- CMakeLists.txt | 4 ++++ stdlib/cmake/modules/AddSwiftStdlib.cmake | 4 ++++ stdlib/cmake/modules/SwiftSource.cmake | 4 ++++ stdlib/public/runtime/ImageInspectionMachO.cpp | 3 ++- utils/build-presets.ini | 1 + utils/build-script-impl | 8 ++++++++ 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9b4b3dbec458..82e07d6244b2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,6 +369,10 @@ option(SWIFT_REPORT_STATISTICS "Create json files which contain internal compilation statistics" FALSE) +option(SWIFT_DISABLE_OBJC_INTEROP + "Disable Objective-C interoperability even on platforms what would normally have it" + FALSE) + # # User-configurable experimental options. Do not use in production builds. # diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 1536bd0422411..7c973d829fbdb 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -329,6 +329,10 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-D_WASI_EMULATED_MMAN") endif() + if(SWIFT_DISABLE_OBJC_INTEROP) + list(APPEND result "-DSWIFT_OBJC_INTEROP=0") + endif() + set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) endfunction() diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index 59ec8d1d2bf46..2fe4ce628afa7 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -450,6 +450,10 @@ function(_compile_swift_files list(APPEND swift_flags "-warn-swift3-objc-inference-complete") endif() + if(SWIFT_DISABLE_OBJC_INTEROP) + list(APPEND swift_flags "-Xfrontend" "-disable-objc-interop") + endif() + list(APPEND swift_flags ${SWIFT_EXPERIMENTAL_EXTRA_FLAGS}) if(SWIFTFILE_OPT_FLAGS) diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp index 81ee6ed3079da..a34246b794901 100644 --- a/stdlib/public/runtime/ImageInspectionMachO.cpp +++ b/stdlib/public/runtime/ImageInspectionMachO.cpp @@ -21,6 +21,7 @@ #if defined(__APPLE__) && defined(__MACH__) #include "ImageInspection.h" +#include "swift/Runtime/Config.h" #include #include #include @@ -121,7 +122,7 @@ void addImageCallback2Sections(const mach_header *mh, intptr_t vmaddr_slide) { } // end anonymous namespace -#if OBJC_ADDLOADIMAGEFUNC_DEFINED +#if OBJC_ADDLOADIMAGEFUNC_DEFINED && SWIFT_OBJC_INTEROP #define REGISTER_FUNC(...) \ if (__builtin_available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)) { \ objc_addLoadImageFunc(__VA_ARGS__); \ diff --git a/utils/build-presets.ini b/utils/build-presets.ini index bf3868dfc97c4..f6fb3497b24e5 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2389,6 +2389,7 @@ enable-experimental-concurrency=0 build-swift-dynamic-sdk-overlay=0 build-swift-dynamic-stdlib=0 build-swift-static-stdlib=1 +swift-objc-interop=0 [preset: stdlib_S_standalone_minimal_macho_x86_64,build] mixin-preset= diff --git a/utils/build-script-impl b/utils/build-script-impl index 7a427b7c43d39..127f6d8c30f32 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -192,6 +192,7 @@ KNOWN_SETTINGS=( report-statistics "0" "set to 1 to generate compilation statistics files for swift libraries" sil-verify-all "0" "If enabled, run the SIL verifier after each transform when building Swift files during this build process" stdlib-deployment-targets "" "space-separated list of targets to configure the Swift standard library to be compiled or cross-compiled for" + swift-objc-interop "" "whether to enable interoperability with Objective-C, default is 1 on Apple platfors, 0 otherwise" ## FREESTANDING Stdlib Options swift-freestanding-sdk "" "which SDK to use when building the FREESTANDING stdlib" @@ -1816,6 +1817,13 @@ for host in "${ALL_HOSTS[@]}"; do ) fi + if [[ "${SWIFT_OBJC_INTEROP}" == "0" ]] ; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_DISABLE_OBJC_INTEROP:BOOL=True + ) + fi + if [[ "${SWIFT_PRIMARY_VARIANT_SDK}" ]] ; then cmake_options=( "${cmake_options[@]}" From 576d0b8d8383745f02f85036d7fb1e5366124d18 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Thu, 13 Aug 2020 15:27:09 -0700 Subject: [PATCH 130/663] [AutoDiff] NFC: fix typos. (#33461) --- lib/SILOptimizer/Mandatory/Differentiation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 5156ffac9e792..eb74975008311 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -1330,7 +1330,7 @@ bool DifferentiationTransformer::processLinearFunctionInst( cast(lfi)); PrettyStackTraceSILFunction fnTrace("...in", lfi->getFunction()); LLVM_DEBUG({ - auto &s = getADDebugStream() << "Processing LinearFunctoinInst:\n"; + auto &s = getADDebugStream() << "Processing LinearFunctionInst:\n"; lfi->printInContext(s); }); @@ -1385,8 +1385,8 @@ void Differentiation::run() { if (auto *dfi = dyn_cast(&i)) { context.getDifferentiableFunctionInstWorklist().push_back(dfi); } else if (auto *lfi = dyn_cast(&i)) { - // If linear map transposition is not enable and an uncanonical - // `linear_function` instruction is encounter, emit a diagnostic. + // If linear map transposition is not enabled and an uncanonical + // `linear_function` instruction is encountered, emit a diagnostic. // FIXME(SR-11850): Finish support for linear map transposition. if (!EnableExperimentalLinearMapTransposition) { if (!lfi->hasTransposeFunction()) { From b6b3d2c5a43dbe50f92710e9dbab50499701a08b Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 13 Aug 2020 15:46:16 -0700 Subject: [PATCH 131/663] [ConstraintLocator] Statically enforce invariants about path element stored values. --- lib/Sema/ConstraintLocator.h | 292 ++++++++++++++--------------------- 1 file changed, 115 insertions(+), 177 deletions(-) diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 8316271de4b7a..eb402ad00909c 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -64,42 +64,6 @@ class ConstraintLocator : public llvm::FoldingSetNode { #include "ConstraintLocatorPathElts.def" }; - /// Determine the number of numeric values used for the given path - /// element kind. - static unsigned numNumericValuesInPathElement(PathElementKind kind) { - switch (kind) { -#define SIMPLE_LOCATOR_PATH_ELT(Name) case Name : -#include "ConstraintLocatorPathElts.def" - case GenericParameter: - case ProtocolRequirement: - case Witness: - case PatternMatch: - return 0; - - case ClosureBody: - case ContextualType: - case OpenedGeneric: - case GenericArgument: - case NamedTupleElement: - case TupleElement: - case KeyPathComponent: - case SynthesizedArgument: - case KeyPathDynamicMember: - case TernaryBranch: - case ArgumentAttribute: - return 1; - - case TypeParameterRequirement: - case ConditionalRequirement: - return 2; - - case ApplyArgToParam: - return 3; - } - - llvm_unreachable("Unhandled PathElementKind in switch."); - } - /// Flags for efficiently recording certain information about a path. /// All of this information should be re-derivable from the path. /// @@ -120,97 +84,18 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// a kind (PathElementKind) and a value used to describe specific /// kinds further (e.g., the position of a tuple element). class PathElement { - /// Describes the kind of data stored here. - enum StoredKind : unsigned char { - StoredPointer, - StoredInteger, - }; - PathElementKind kind; - /// The actual storage for the path element, which involves both a - /// storage kind and a value. - /// - /// The current storage involves a three-bit "storage kind", which selects - /// among the possible value stores. The value stores can either be a - /// pointer or an unsigned int. Use \c getValue or \c getStoredPointer - /// to work with this value. - /// - /// \note The "storage kind" is stored in the \c storedKind field. - uint64_t storage : 61; - - /// The kind of value stored in \c storage. Valid values are those - /// from the StoredKind enum. - uint64_t storedKind : 3; - - /// Retrieve a value associated with the path element. - unsigned getValue(unsigned index) const { - unsigned numValues = numNumericValuesInPathElement(getKind()); - assert(index < numValues && "Index out of range for path element value"); - - // We pack values into 16 bit components of the storage, with value0 - // being stored in the upper bits, valueN in the lower bits. Therefore we - // need to shift out any extra values in the lower bits. - auto extraValues = numValues - index - 1; - auto value = storage >> (extraValues * 16); - return value & 0xFFFF; - } - - PathElement(PathElementKind kind, unsigned value) - : kind(kind), storage(value), storedKind(StoredInteger) - { - assert(numNumericValuesInPathElement(kind) == 1 && - "Path element kind does not require 1 value"); - assert(value == getValue(0) && "value truncated"); - } - - PathElement(PathElementKind kind, unsigned value0, unsigned value1) - : kind(kind), storage(value0 << 16 | value1), - storedKind(StoredInteger) - { - assert(numNumericValuesInPathElement(kind) == 2 && - "Path element kind does not require 2 values"); - assert(value0 == getValue(0) && "value0 truncated"); - assert(value1 == getValue(1) && "value1 truncated"); - } - - PathElement(PathElementKind kind, uint64_t value0, uint64_t value1, uint64_t value2) - : kind(kind), storage(value0 << 32 | value1 << 16 | value2), - storedKind(StoredInteger) { - assert(numNumericValuesInPathElement(kind) == 3 && - "Path element kind does not require 3 values"); - assert(value0 == getValue(0) && "value0 truncated"); - assert(value1 == getValue(1) && "value1 truncated"); - assert(value2 == getValue(2) && "value2 truncated"); - } - - /// Store a path element with an associated pointer, accessible using - /// \c getStoredPointer. - template - PathElement(PathElementKind kind, T *ptr) - : kind(kind), storage((reinterpret_cast(ptr) >> 3)), - storedKind(StoredPointer) { - assert(ptr == getStoredPointer()); - } - - /// Retrieve an associated pointer for the element. The type \c T must match - /// the type used when creating the path element. - template - T *getStoredPointer() const { - assert(storedKind == StoredPointer); - return reinterpret_cast(storage << 3); - } + /// The storage for the path element value. The value stores can either + /// be a pointer or an unsigned int. Only custom path elements store values. + uint64_t storage; public: #define LOCATOR_PATH_ELT(Name) class Name; #include "ConstraintLocatorPathElts.def" - PathElement(PathElementKind kind) - : kind(kind), storage(0), storedKind(StoredInteger) - { - assert(numNumericValuesInPathElement(kind) == 0 && - "Path element requires value"); - } + PathElement(PathElementKind kind, uint64_t storage = 0) + : kind(kind), storage(storage) {} /// Retrieve the kind of path element. PathElementKind getKind() const { return kind; } @@ -552,20 +437,76 @@ public: \ }; #include "ConstraintLocatorPathElts.def" +/// A base class for custom path elements that store numeric values. +template +class StoredIntegerElement: public LocatorPathElt { +public: + template ::type> + StoredIntegerElement(ConstraintLocator::PathElementKind kind, unsigned value) + : LocatorPathElt(kind, value) { + assert(value == getValue<0>() && "value truncated"); + } + + template ::type> + StoredIntegerElement(ConstraintLocator::PathElementKind kind, unsigned value0, unsigned value1) + : LocatorPathElt(kind, (value0 << 16 | value1)) { + assert(value0 == getValue<0>() && "value0 truncated"); + assert(value1 == getValue<1>() && "value1 truncated"); + } + + template ::type> + StoredIntegerElement(ConstraintLocator::PathElementKind kind, unsigned value0, + unsigned value1, unsigned value2) + : LocatorPathElt(kind, uint64_t(value0) << 32 | uint64_t(value1) << 16 | uint64_t(value2)) { + assert(value0 == getValue<0>() && "value0 truncated"); + assert(value1 == getValue<1>() && "value1 truncated"); + assert(value2 == getValue<2>() && "value2 truncated"); + } + + /// Retrieve a value associated with the path element. + template ::type> + unsigned getValue() const { + // We pack values into 16 bit components of the storage, with value0 + // being stored in the upper bits, valueN in the lower bits. Therefore we + // need to shift out any extra values in the lower bits. + auto extraValues = NumValues - Index - 1; + auto value = getRawStorage() >> (extraValues * 16); + return value & 0xFFFF; + } +}; + +/// A base class for custom path elements that store a pointer. +template +class StoredPointerElement: public LocatorPathElt { +public: + StoredPointerElement(ConstraintLocator::PathElementKind kind, const T *ptr) + : LocatorPathElt(kind, reinterpret_cast(ptr)) { + assert(ptr == getStoredPointer()); + } + + /// Retrieve the associated pointer for the element. + T *getStoredPointer() const { return reinterpret_cast(getRawStorage()); } +}; + // The following LocatorPathElt subclasses are used to expose accessors for // specific path element information. They shouldn't introduce additional -// storage, as LocatorPathElt gets passed about by value. +// storage, as LocatorPathElt gets passed about by value. Custom path elements +// should subclass StoredIntegerElement to store unsigned values, or StoredPointerElement +// to store pointer values. -class LocatorPathElt::ApplyArgToParam final : public LocatorPathElt { +class LocatorPathElt::ApplyArgToParam final : public StoredIntegerElement<3> { public: ApplyArgToParam(unsigned argIdx, unsigned paramIdx, ParameterTypeFlags flags) - : LocatorPathElt(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx, - flags.toRaw()) {} + : StoredIntegerElement(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx, flags.toRaw()) {} - unsigned getArgIdx() const { return getValue(0); } - unsigned getParamIdx() const { return getValue(1); } + unsigned getArgIdx() const { return getValue<0>(); } + unsigned getParamIdx() const { return getValue<1>(); } ParameterTypeFlags getParameterFlags() const { - return ParameterTypeFlags::fromRaw(getValue(2)); + return ParameterTypeFlags::fromRaw(getValue<2>()); } static bool classof(const LocatorPathElt *elt) { @@ -573,12 +514,12 @@ class LocatorPathElt::ApplyArgToParam final : public LocatorPathElt { } }; -class LocatorPathElt::SynthesizedArgument final : public LocatorPathElt { +class LocatorPathElt::SynthesizedArgument final : public StoredIntegerElement<1> { public: SynthesizedArgument(unsigned index) - : LocatorPathElt(ConstraintLocator::SynthesizedArgument, index) {} + : StoredIntegerElement(ConstraintLocator::SynthesizedArgument, index) {} - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::SynthesizedArgument; @@ -586,15 +527,15 @@ class LocatorPathElt::SynthesizedArgument final : public LocatorPathElt { }; /// Abstract superclass for any kind of tuple element. -class LocatorPathElt::AnyTupleElement : public LocatorPathElt { +class LocatorPathElt::AnyTupleElement : public StoredIntegerElement<1> { protected: AnyTupleElement(PathElementKind kind, unsigned index) - : LocatorPathElt(kind, index) { + : StoredIntegerElement(kind, index) { assert(classof(this) && "classof needs updating"); } public: - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->is() || @@ -624,24 +565,24 @@ class LocatorPathElt::NamedTupleElement final } }; -class LocatorPathElt::KeyPathComponent final : public LocatorPathElt { +class LocatorPathElt::KeyPathComponent final : public StoredIntegerElement<1> { public: KeyPathComponent(unsigned index) - : LocatorPathElt(ConstraintLocator::KeyPathComponent, index) {} + : StoredIntegerElement(ConstraintLocator::KeyPathComponent, index) {} - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::KeyPathComponent; } }; -class LocatorPathElt::GenericArgument final : public LocatorPathElt { +class LocatorPathElt::GenericArgument final : public StoredIntegerElement<1> { public: GenericArgument(unsigned index) - : LocatorPathElt(ConstraintLocator::GenericArgument, index) {} + : StoredIntegerElement(ConstraintLocator::GenericArgument, index) {} - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::GenericArgument; @@ -650,17 +591,17 @@ class LocatorPathElt::GenericArgument final : public LocatorPathElt { /// Abstract superclass for any kind of element that describes a requirement /// placed on a type within a requirements clause. -class LocatorPathElt::AnyRequirement : public LocatorPathElt { +class LocatorPathElt::AnyRequirement : public StoredIntegerElement<2> { protected: AnyRequirement(PathElementKind kind, unsigned index, RequirementKind reqKind) - : LocatorPathElt(kind, index, static_cast(reqKind)) { + : StoredIntegerElement(kind, index, static_cast(reqKind)) { assert(classof(this) && "classof needs updating"); } public: - unsigned getIndex() const { return getValue(0); } + unsigned getIndex() const { return getValue<0>(); } RequirementKind getRequirementKind() const { - return static_cast(getValue(1)); + return static_cast(getValue<1>()); } static bool classof(const LocatorPathElt *elt) { @@ -693,69 +634,67 @@ class LocatorPathElt::TypeParameterRequirement final } }; -class LocatorPathElt::ClosureBody final : public LocatorPathElt { +class LocatorPathElt::ClosureBody final : public StoredIntegerElement<1> { public: ClosureBody(bool hasExplicitReturn = false) - : LocatorPathElt(ConstraintLocator::ClosureBody, - hasExplicitReturn) {} + : StoredIntegerElement(ConstraintLocator::ClosureBody, hasExplicitReturn) {} /// Indicates whether body of the closure has any `return` statements. - bool hasExplicitReturn() const { return bool(getValue(0)); } + bool hasExplicitReturn() const { return bool(getValue()); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::ClosureBody; } }; -class LocatorPathElt::ContextualType final : public LocatorPathElt { +class LocatorPathElt::ContextualType final : public StoredIntegerElement<1> { public: ContextualType(bool isForSingleExprFunction = false) - : LocatorPathElt(ConstraintLocator::ContextualType, - isForSingleExprFunction) {} + : StoredIntegerElement(ConstraintLocator::ContextualType, isForSingleExprFunction) {} /// Whether this element points to the contextual type associated with the /// result of a single expression function. - bool isForSingleExprFunction() const { return bool(getValue(0)); } + bool isForSingleExprFunction() const { return bool(getValue()); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::ContextualType; } }; -class LocatorPathElt::Witness final : public LocatorPathElt { +class LocatorPathElt::Witness final : public StoredPointerElement { public: Witness(ValueDecl *witness) - : LocatorPathElt(PathElementKind::Witness, witness) {} + : StoredPointerElement(PathElementKind::Witness, witness) {} - ValueDecl *getDecl() const { return getStoredPointer(); } + ValueDecl *getDecl() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == PathElementKind::Witness; } }; -class LocatorPathElt::ProtocolRequirement final : public LocatorPathElt { +class LocatorPathElt::ProtocolRequirement final : public StoredPointerElement { public: ProtocolRequirement(ValueDecl *decl) - : LocatorPathElt(PathElementKind::ProtocolRequirement, decl) {} + : StoredPointerElement(PathElementKind::ProtocolRequirement, decl) {} - ValueDecl *getDecl() const { return getStoredPointer(); } + ValueDecl *getDecl() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == PathElementKind::ProtocolRequirement; } }; -class LocatorPathElt::GenericParameter final : public LocatorPathElt { +class LocatorPathElt::GenericParameter final : public StoredPointerElement { public: GenericParameter(GenericTypeParamType *type) - : LocatorPathElt(PathElementKind::GenericParameter, type) { + : StoredPointerElement(PathElementKind::GenericParameter, type) { static_assert(alignof(GenericTypeParamType) >= 4, "archetypes insufficiently aligned"); } GenericTypeParamType *getType() const { - return getStoredPointer(); + return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { @@ -763,13 +702,13 @@ class LocatorPathElt::GenericParameter final : public LocatorPathElt { } }; -class LocatorPathElt::OpenedGeneric final : public LocatorPathElt { +class LocatorPathElt::OpenedGeneric final : public StoredPointerElement { public: OpenedGeneric(GenericSignature sig) - : LocatorPathElt(PathElementKind::OpenedGeneric, sig.getPointer()) {} + : StoredPointerElement(PathElementKind::OpenedGeneric, sig.getPointer()) {} GenericSignature getSignature() const { - return getStoredPointer(); + return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { @@ -777,13 +716,13 @@ class LocatorPathElt::OpenedGeneric final : public LocatorPathElt { } }; -class LocatorPathElt::KeyPathDynamicMember final : public LocatorPathElt { +class LocatorPathElt::KeyPathDynamicMember final : public StoredPointerElement { public: KeyPathDynamicMember(NominalTypeDecl *keyPathDecl) - : LocatorPathElt(PathElementKind::KeyPathDynamicMember, keyPathDecl) {} + : StoredPointerElement(PathElementKind::KeyPathDynamicMember, keyPathDecl) {} NominalTypeDecl *getKeyPathDecl() const { - return getStoredPointer(); + return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { @@ -791,43 +730,42 @@ class LocatorPathElt::KeyPathDynamicMember final : public LocatorPathElt { } }; -class LocatorPathElt::TernaryBranch final : public LocatorPathElt { +class LocatorPathElt::TernaryBranch final : public StoredIntegerElement<1> { public: TernaryBranch(bool side) - : LocatorPathElt(ConstraintLocator::TernaryBranch, side) {} + : StoredIntegerElement(ConstraintLocator::TernaryBranch, side) {} - bool forThen() const { return bool(getValue(0)); } + bool forThen() const { return bool(getValue()); } - bool forElse() const { return !bool(getValue(0)); } + bool forElse() const { return !bool(getValue()); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::TernaryBranch; } }; -class LocatorPathElt::PatternMatch final : public LocatorPathElt { +class LocatorPathElt::PatternMatch final : public StoredPointerElement { public: PatternMatch(Pattern *pattern) - : LocatorPathElt(PathElementKind::PatternMatch, pattern) {} + : StoredPointerElement(PathElementKind::PatternMatch, pattern) {} - Pattern *getPattern() const { return getStoredPointer(); } + Pattern *getPattern() const { return getStoredPointer(); } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::PatternMatch; } }; -class LocatorPathElt::ArgumentAttribute final : public LocatorPathElt { +class LocatorPathElt::ArgumentAttribute final : public StoredIntegerElement<1> { public: enum Attribute : uint8_t { InOut, Escaping }; private: ArgumentAttribute(Attribute attr) - : LocatorPathElt(ConstraintLocator::ArgumentAttribute, - static_cast(attr)) {} + : StoredIntegerElement(ConstraintLocator::ArgumentAttribute, static_cast(attr)) {} public: - Attribute getAttr() const { return static_cast(getValue(0)); } + Attribute getAttr() const { return static_cast(getValue()); } static ArgumentAttribute forInOut() { return ArgumentAttribute(Attribute::InOut); From c25c180c08812ab5ba573b8d8342a81174d50b1e Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 12 Aug 2020 18:20:19 -0700 Subject: [PATCH 132/663] [IRGen] Erase thunks before emission. Previously, a call to emitMethodLookupFunction or emitDispatchThunk would always simply emit a function, even if it had previously been emitted. That was a problem since these emissions are triggered by emitting class type context descriptors which can now be lazily reemitted upon encountering prespecialized metadata. Here, that behavior is changed to delete the old body, if any, before emitting the body again. --- lib/IRGen/GenThunk.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/IRGen/GenThunk.cpp b/lib/IRGen/GenThunk.cpp index 74d862df8d567..d18d8846348dc 100644 --- a/lib/IRGen/GenThunk.cpp +++ b/lib/IRGen/GenThunk.cpp @@ -102,6 +102,9 @@ static FunctionPointer lookupMethod(IRGenFunction &IGF, SILDeclRef declRef) { void IRGenModule::emitDispatchThunk(SILDeclRef declRef) { auto *f = getAddrOfDispatchThunk(declRef, ForDefinition); + if (!f->isDeclaration()) { + f->deleteBody(); + } IRGenFunction IGF(*this, f); @@ -163,6 +166,9 @@ IRGenModule::getAddrOfMethodLookupFunction(ClassDecl *classDecl, void IRGenModule::emitMethodLookupFunction(ClassDecl *classDecl) { auto *f = getAddrOfMethodLookupFunction(classDecl, ForDefinition); + if (!f->isDeclaration()) { + f->deleteBody(); + } IRGenFunction IGF(*this, f); From 3ad2777a68daf66475024abfb5743bd3d95c00b7 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 13 Aug 2020 16:03:04 -0700 Subject: [PATCH 133/663] [IRGen] Erase nonoverride descriptor on emission. Previously, emitting the descriptor for a nonoverride method always simply emitted, even if it had previously been emitted. That was not a problem before, but is now that class type context descriptors can be reemitted upon encountering metadata prespecializations. Here, the behavior is changed to delete the old definition before emitting the new definition. --- lib/IRGen/GenMeta.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index e6812490abbff..b6fa3419c45b1 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -300,6 +300,10 @@ static void buildMethodDescriptorFields(IRGenModule &IGM, void IRGenModule::emitNonoverriddenMethodDescriptor(const SILVTable *VTable, SILDeclRef declRef) { + auto entity = LinkEntity::forMethodDescriptor(declRef); + + auto *var = cast(getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo())); + var->setInitializer(nullptr); ConstantInitBuilder ib(*this); ConstantStructBuilder sb(ib.beginStruct(MethodDescriptorStructTy)); @@ -308,7 +312,6 @@ void IRGenModule::emitNonoverriddenMethodDescriptor(const SILVTable *VTable, auto init = sb.finishAndCreateFuture(); - auto entity = LinkEntity::forMethodDescriptor(declRef); getAddrOfLLVMVariable(entity, init, DebugTypeInfo()); } From 00e143c0aa2965b1efc044a10f2cd2cc67e8eb37 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 13 Aug 2020 17:38:02 -0700 Subject: [PATCH 134/663] [Runtime] Add trailing prespecializations to type descriptor. The attachment of the canonical prespecializations to the generic type will enable runtime functions to look through the canonical prespecializations in order to return them (getGenericMetadata) and register them with the runtime (getSpecializedGenericMetadata). --- include/swift/ABI/Metadata.h | 182 ++++++++++++++++++++++++++++- include/swift/ABI/MetadataValues.h | 6 + 2 files changed, 182 insertions(+), 6 deletions(-) diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 2f6d07561224b..0ac4ab8943c42 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -3772,6 +3772,21 @@ struct TargetSingletonMetadataInitialization { const TargetTypeContextDescriptor *description) const; }; +template +struct TargetCanonicalSpecializedMetadatasListCount { + uint32_t count; +}; + +template +struct TargetCanonicalSpecializedMetadatasListEntry { + TargetRelativeDirectPointer, /*Nullable*/ false> metadata; +}; + +template +struct TargetCanonicalSpecializedMetadataAccessorsListEntry { + TargetRelativeDirectPointer accessor; +}; + template class TargetTypeContextDescriptor : public TargetContextDescriptor { @@ -3821,6 +3836,10 @@ class TargetTypeContextDescriptor return getTypeContextDescriptorFlags().hasForeignMetadataInitialization(); } + bool hasCanonicicalMetadataPrespecializations() const { + return getTypeContextDescriptorFlags().hasCanonicalMetadataPrespecializations(); + } + /// Given that this type has foreign metadata initialization, return the /// control structure for it. const TargetForeignMetadataInitialization & @@ -3853,6 +3872,9 @@ class TargetTypeContextDescriptor return words + offset; } + const llvm::ArrayRef, /*Nullable*/ false>> + getCanonicicalMetadataPrespecializations() const; + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() >= ContextDescriptorKind::Type_First && cd->getKind() <= ContextDescriptorKind::Type_Last; @@ -3990,7 +4012,10 @@ class TargetClassDescriptor final TargetMethodDescriptor, TargetOverrideTableHeader, TargetMethodOverrideDescriptor, - TargetObjCResilientClassStubInfo> { + TargetObjCResilientClassStubInfo, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry, + TargetCanonicalSpecializedMetadataAccessorsListEntry> { private: using TrailingGenericContextObjects = swift::TrailingGenericContextObjects, @@ -4002,7 +4027,10 @@ class TargetClassDescriptor final TargetMethodDescriptor, TargetOverrideTableHeader, TargetMethodOverrideDescriptor, - TargetObjCResilientClassStubInfo>; + TargetObjCResilientClassStubInfo, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry, + TargetCanonicalSpecializedMetadataAccessorsListEntry>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; @@ -4020,6 +4048,16 @@ class TargetClassDescriptor final TargetSingletonMetadataInitialization; using ObjCResilientClassStubInfo = TargetObjCResilientClassStubInfo; + using Metadata = + TargetRelativeDirectPointer, /*Nullable*/ false>; + using MetadataListCount = + TargetCanonicalSpecializedMetadatasListCount; + using MetadataListEntry = + TargetCanonicalSpecializedMetadatasListEntry; + using MetadataAccessor = + TargetRelativeDirectPointer; + using MetadataAccessorListEntry = + TargetCanonicalSpecializedMetadataAccessorsListEntry; using StoredPointer = typename Runtime::StoredPointer; using StoredPointerDifference = typename Runtime::StoredPointerDifference; @@ -4139,6 +4177,24 @@ class TargetClassDescriptor final return hasObjCResilientClassStub() ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + 1 + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + public: const TargetRelativeDirectPointer & getResilientSuperclass() const { @@ -4276,6 +4332,32 @@ class TargetClassDescriptor final ->Stub.get(); } + llvm::ArrayRef getCanonicicalMetadataPrespecializations() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + + llvm::ArrayRef getCanonicalMetadataPrespecializationAccessors() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Class; } @@ -4301,19 +4383,29 @@ class TargetStructDescriptor final TargetTypeGenericContextDescriptorHeader, /*additional trailing objects*/ TargetForeignMetadataInitialization, - TargetSingletonMetadataInitialization> { + TargetSingletonMetadataInitialization, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry> { public: using ForeignMetadataInitialization = TargetForeignMetadataInitialization; using SingletonMetadataInitialization = TargetSingletonMetadataInitialization; + using Metadata = + TargetRelativeDirectPointer, /*Nullable*/ false>; + using MetadataListCount = + TargetCanonicalSpecializedMetadatasListCount; + using MetadataListEntry = + TargetCanonicalSpecializedMetadatasListEntry; private: using TrailingGenericContextObjects = swift::TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader, ForeignMetadataInitialization, - SingletonMetadataInitialization>; + SingletonMetadataInitialization, + MetadataListCount, + MetadataListEntry>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; @@ -4331,6 +4423,18 @@ class TargetStructDescriptor final return this->hasSingletonMetadataInitialization() ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + 1 + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + public: using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContextHeader; @@ -4363,6 +4467,19 @@ class TargetStructDescriptor final return TargetStructMetadata::getGenericArgumentOffset(); } + llvm::ArrayRef getCanonicicalMetadataPrespecializations() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Struct; } @@ -4377,19 +4494,29 @@ class TargetEnumDescriptor final TargetTypeGenericContextDescriptorHeader, /*additional trailing objects*/ TargetForeignMetadataInitialization, - TargetSingletonMetadataInitialization> { + TargetSingletonMetadataInitialization, + TargetCanonicalSpecializedMetadatasListCount, + TargetCanonicalSpecializedMetadatasListEntry> { public: using SingletonMetadataInitialization = TargetSingletonMetadataInitialization; using ForeignMetadataInitialization = TargetForeignMetadataInitialization; + using Metadata = + TargetRelativeDirectPointer, /*Nullable*/ false>; + using MetadataListCount = + TargetCanonicalSpecializedMetadatasListCount; + using MetadataListEntry = + TargetCanonicalSpecializedMetadatasListEntry; private: using TrailingGenericContextObjects = swift::TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader, ForeignMetadataInitialization, - SingletonMetadataInitialization>; + SingletonMetadataInitialization, + MetadataListCount, + MetadataListEntry>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; @@ -4407,6 +4534,18 @@ class TargetEnumDescriptor final return this->hasSingletonMetadataInitialization() ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + 1 + : 0; + } + + size_t numTrailingObjects(OverloadToken) const { + return this->hasCanonicicalMetadataPrespecializations() ? + this->template getTrailingObjects()->count + : 0; + } + public: using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContextHeader; @@ -4453,6 +4592,19 @@ class TargetEnumDescriptor final return *this->template getTrailingObjects(); } + llvm::ArrayRef getCanonicicalMetadataPrespecializations() const { + if (!this->hasCanonicicalMetadataPrespecializations()) { + return {}; + } + + auto *listCount = this->template getTrailingObjects(); + auto *list = this->template getTrailingObjects(); + return llvm::ArrayRef( + reinterpret_cast(list), + listCount->count + ); + } + static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Enum; } @@ -4587,6 +4739,24 @@ TargetTypeContextDescriptor::getSingletonMetadataInitialization() const } } +template +inline const llvm::ArrayRef, /*Nullable*/ false>> +TargetTypeContextDescriptor::getCanonicicalMetadataPrespecializations() const { + switch (this->getKind()) { + case ContextDescriptorKind::Enum: + return llvm::cast>(this) + ->getCanonicicalMetadataPrespecializations(); + case ContextDescriptorKind::Struct: + return llvm::cast>(this) + ->getCanonicicalMetadataPrespecializations(); + case ContextDescriptorKind::Class: + return llvm::cast>(this) + ->getCanonicicalMetadataPrespecializations(); + default: + swift_runtime_unreachable("Not a type context descriptor."); + } +} + /// An entry in the chain of dynamic replacement functions. struct DynamicReplacementChainEntry { void *implementationFunction; diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index b5b62a7edf5f0..54232972ca9fd 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -1326,6 +1326,10 @@ class TypeContextDescriptorFlags : public FlagSet { /// Meaningful for all type-descriptor kinds. HasImportInfo = 2, + /// Set if the type descriptor has a pointer to a list of canonical + /// prespecializations. + HasCanonicalMetadataPrespecializations = 3, + // Type-specific flags: /// The kind of reference that this class makes to its resilient superclass @@ -1393,6 +1397,8 @@ class TypeContextDescriptorFlags : public FlagSet { FLAGSET_DEFINE_FLAG_ACCESSORS(HasImportInfo, hasImportInfo, setHasImportInfo) + FLAGSET_DEFINE_FLAG_ACCESSORS(HasCanonicalMetadataPrespecializations, hasCanonicalMetadataPrespecializations, setHasCanonicalMetadataPrespecializations) + FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable, class_hasVTable, class_setHasVTable) From 5114f22e5e75ac821953708fa907876fa4b9ebbd Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 13 Aug 2020 17:44:05 -0700 Subject: [PATCH 135/663] [metadata prespecialization] Reemit dependent values. The metadata accessor and type context descriptor for a nominal type both depend on canonical metadata--the former because it returns those metadata, the latter because it has them as trailing objects. Here, the work is done to reemit those values when new canonical prespecialized metadata are encountered. --- lib/IRGen/GenDecl.cpp | 98 ++++++++++++++----- lib/IRGen/GenMeta.cpp | 60 ++++++++++++ lib/IRGen/IRGenModule.h | 37 ++++--- lib/IRGen/MetadataRequest.cpp | 29 ++++-- ...nct_use-struct-outmodule-othermodule.swift | 54 +++++++++- ...inct_use-struct-outmodule-samemodule.swift | 55 ++++++++++- ...le_samemodule-2arg_protocol_inmodule.swift | 57 ++++++++++- ...-2arg_protocol_outmodule_othermodule.swift | 57 ++++++++++- ...e-2arg_protocol_outmodule_samemodule.swift | 57 ++++++++++- ...le-2arg_struct_outmodule_othermodule.swift | 65 +++++++++++- ...ule-2arg_struct_outmodule_samemodule.swift | 65 +++++++++++- ...-struct-outmodule-frozen-othermodule.swift | 55 ++++++++++- ...e-struct-outmodule-frozen-samemodule.swift | 55 ++++++++++- 13 files changed, 669 insertions(+), 75 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index ab718f80c5173..37bb9cfd073f4 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1164,18 +1164,42 @@ void IRGenerator::emitTypeMetadataRecords() { } } +void IRGenerator:: + deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, + NominalTypeDecl &decl) { + // The accessor depends on canonical metadata records because they are + // returned from the function when the arguments match. + // + // TODO: Once work of looking through canonical prespecialized metadata has + // been moved into getGenericMetadata, this reemission will no longer + // be necessary. + auto *accessor = IGM.getAddrOfTypeMetadataAccessFunction( + decl.getDeclaredType()->getCanonicalType(), NotForDefinition); + accessor->deleteBody(); + IGM.IRGen.noteUseOfMetadataAccessor(&decl); + + // The type context descriptor depends on canonical metadata records because + // pointers to them are attached as trailing objects to it. + // + // Don't call + // + // noteUseOfTypeContextDescriptor + // + // here because we don't want to reemit metadata. + emitLazyTypeContextDescriptor(IGM, &decl, RequireMetadata); +} + /// Emit any lazy definitions (of globals or functions or whatever /// else) that we require. void IRGenerator::emitLazyDefinitions() { while (!LazyTypeMetadata.empty() || !LazySpecializedTypeMetadataRecords.empty() || !LazyTypeContextDescriptors.empty() || - !LazyOpaqueTypeDescriptors.empty() || - !LazyFieldDescriptors.empty() || - !LazyFunctionDefinitions.empty() || - !LazyWitnessTables.empty() || - !LazyCanonicalSpecializedMetadataAccessors.empty()) { - + !LazyOpaqueTypeDescriptors.empty() || !LazyFieldDescriptors.empty() || + !LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() || + !LazyCanonicalSpecializedMetadataAccessors.empty() || + !LazyMetadataAccessors.empty()) { // Emit any lazy type metadata we require. while (!LazyTypeMetadata.empty()) { NominalTypeDecl *type = LazyTypeMetadata.pop_back_val(); @@ -1187,10 +1211,23 @@ void IRGenerator::emitLazyDefinitions() { emitLazyTypeMetadata(*IGM.get(), type); } while (!LazySpecializedTypeMetadataRecords.empty()) { - CanType type = LazySpecializedTypeMetadataRecords.pop_back_val(); - auto *nominal = type->getNominalOrBoundGenericNominal(); - CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); - emitLazySpecializedGenericTypeMetadata(*IGM.get(), type); + CanType theType; + TypeMetadataCanonicality canonicality; + std::tie(theType, canonicality) = + LazySpecializedTypeMetadataRecords.pop_back_val(); + auto *nominal = theType->getNominalOrBoundGenericNominal(); + CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext()); + auto &IGM = *IGMPtr.get(); + // A new canonical prespecialized metadata changes both the type + // descriptor (adding a new entry to the trailing list of metadata) and + // the metadata accessor (adding a new list of generic arguments against + // which to compare the arguments to the function). Consequently, it is + // necessary to force these to be reemitted. + if (canonicality == TypeMetadataCanonicality::Canonical) { + deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IGM, theType, *nominal); + } + emitLazySpecializedGenericTypeMetadata(IGM, theType); } while (!LazyTypeContextDescriptors.empty()) { NominalTypeDecl *type = LazyTypeContextDescriptors.pop_back_val(); @@ -1236,17 +1273,25 @@ void IRGenerator::emitLazyDefinitions() { LazyCanonicalSpecializedMetadataAccessors.pop_back_val(); auto *nominal = theType->getAnyNominal(); assert(nominal); + CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext()); + auto &IGM = *IGMPtr.get(); + // TODO: Once non-canonical accessors are available, this variable should + // reflect the canonicality of the accessor rather than always being + // canonical. + auto canonicality = TypeMetadataCanonicality::Canonical; + if (canonicality == TypeMetadataCanonicality::Canonical) { + deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IGM, theType, *nominal); + } + emitLazyCanonicalSpecializedMetadataAccessor(IGM, theType); + } + while (!LazyMetadataAccessors.empty()) { + NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val(); CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); - emitLazyCanonicalSpecializedMetadataAccessor(*IGM.get(), theType); + emitLazyMetadataAccessor(*IGM.get(), nominal); } } - while (!LazyMetadataAccessors.empty()) { - NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val(); - CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); - emitLazyMetadataAccessor(*IGM.get(), nominal); - } - FinishedEmittingLazyDefinitions = true; } @@ -1442,17 +1487,19 @@ static bool typeKindCanBePrespecialized(TypeKind theKind) { } } -void IRGenerator::noteUseOfSpecializedGenericTypeMetadata(CanType type) { - assert(typeKindCanBePrespecialized(type->getKind())); - auto key = type->getAnyNominal(); +void IRGenerator::noteUseOfSpecializedGenericTypeMetadata( + IRGenModule &IGM, CanType theType, TypeMetadataCanonicality canonicality) { + assert(typeKindCanBePrespecialized(theType->getKind())); + auto key = theType->getAnyNominal(); assert(key); assert(key->isGenericContext()); - auto &enqueuedSpecializedTypes = CanonicalSpecializationsForGenericTypes[key]; + auto &enqueuedSpecializedTypes = + MetadataPrespecializationsForGenericTypes[key]; if (llvm::all_of(enqueuedSpecializedTypes, - [&](CanType enqueued) { return enqueued != type; })) { + [&](auto enqueued) { return enqueued.first != theType; })) { assert(!FinishedEmittingLazyDefinitions); - LazySpecializedTypeMetadataRecords.push_back(type); - enqueuedSpecializedTypes.push_back(type); + LazySpecializedTypeMetadataRecords.push_back({theType, canonicality}); + enqueuedSpecializedTypes.push_back({theType, canonicality}); } } @@ -4032,7 +4079,8 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, if (shouldPrespecializeGenericMetadata()) { if (auto nominal = concreteType->getAnyNominal()) { if (nominal->isGenericContext()) { - IRGen.noteUseOfSpecializedGenericTypeMetadata(concreteType); + IRGen.noteUseOfSpecializedGenericTypeMetadata(*this, concreteType, + canonicality); } } } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index b6fa3419c45b1..02bb05ed18c15 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1218,6 +1218,7 @@ namespace { void setCommonFlags(TypeContextDescriptorFlags &flags) { setClangImportedFlags(flags); setMetadataInitializationKind(flags); + setHasCanonicalMetadataPrespecializations(flags); } void setClangImportedFlags(TypeContextDescriptorFlags &flags) { @@ -1251,6 +1252,19 @@ namespace { flags.setMetadataInitialization(MetadataInitialization); } + void setHasCanonicalMetadataPrespecializations(TypeContextDescriptorFlags &flags) { + flags.setHasCanonicalMetadataPrespecializations(hasCanonicalMetadataPrespecializations()); + } + + bool hasCanonicalMetadataPrespecializations() { + return IGM.shouldPrespecializeGenericMetadata() && + llvm::any_of(IGM.IRGen.metadataPrespecializationsForType(Type), + [](auto pair) { + return pair.second == + TypeMetadataCanonicality::Canonical; + }); + } + void maybeAddMetadataInitialization() { switch (MetadataInitialization) { case TypeContextDescriptorFlags::NoMetadataInitialization: @@ -1310,6 +1324,28 @@ namespace { addIncompleteMetadata(); } + void maybeAddCanonicalMetadataPrespecializations() { + if (Type->isGenericContext() && hasCanonicalMetadataPrespecializations()) { + asImpl().addCanonicalMetadataPrespecializations(); + } + } + + void addCanonicalMetadataPrespecializations() { + auto specializations = IGM.IRGen.metadataPrespecializationsForType(Type); + auto count = llvm::count_if(specializations, [](auto pair) { + return pair.second == TypeMetadataCanonicality::Canonical; + }); + B.addInt32(count); + for (auto pair : specializations) { + if (pair.second != TypeMetadataCanonicality::Canonical) { + continue; + } + auto specialization = pair.first; + auto *metadata = IGM.getAddrOfTypeMetadata(specialization); + B.addRelativeAddress(metadata); + } + } + // Subclasses should provide: // ContextDescriptorKind getContextKind(); // void addLayoutInfo(); @@ -1337,6 +1373,11 @@ namespace { FieldVectorOffset = layout.getFieldOffsetVectorOffset().getStatic(); } + void layout() { + super::layout(); + maybeAddCanonicalMetadataPrespecializations(); + } + ContextDescriptorKind getContextKind() { return ContextDescriptorKind::Struct; } @@ -1397,6 +1438,11 @@ namespace { if (layout.hasPayloadSizeOffset()) PayloadSizeOffset = layout.getPayloadSizeOffset().getStatic(); } + + void layout() { + super::layout(); + maybeAddCanonicalMetadataPrespecializations(); + } ContextDescriptorKind getContextKind() { return ContextDescriptorKind::Enum; @@ -1511,6 +1557,7 @@ namespace { addVTable(); addOverrideTable(); addObjCResilientClassStubInfo(); + maybeAddCanonicalMetadataPrespecializations(); } void addIncompleteMetadataOrRelocationFunction() { @@ -1783,6 +1830,19 @@ namespace { getType(), NotForDefinition, TypeMetadataAddress::AddressPoint)); } + + void addCanonicalMetadataPrespecializations() { + super::addCanonicalMetadataPrespecializations(); + auto specializations = IGM.IRGen.metadataPrespecializationsForType(Type); + for (auto pair : specializations) { + if (pair.second != TypeMetadataCanonicality::Canonical) { + continue; + } + auto specialization = pair.first; + auto *function = IGM.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction(specialization, NotForDefinition); + B.addRelativeAddress(function); + } + } }; class OpaqueTypeDescriptorBuilder diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 772301bd07e97..d9de7a41bb624 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -192,6 +192,11 @@ enum RequireMetadata_t : bool { RequireMetadata = true }; +enum class TypeMetadataCanonicality : bool { + Noncanonical, + Canonical, +}; + /// The principal singleton which manages all of IR generation. /// /// The IRGenerator delegates the emission of different top-level entities @@ -259,17 +264,20 @@ class IRGenerator { /// queued up. llvm::SmallPtrSet LazilyEmittedFieldMetadata; - /// Maps every generic type that is specialized within the module to its - /// specializations. - llvm::DenseMap> - CanonicalSpecializationsForGenericTypes; + /// Maps every generic type whose metadata is specialized within the module + /// to its specializations. + llvm::DenseMap< + NominalTypeDecl *, + llvm::SmallVector, 4>> + MetadataPrespecializationsForGenericTypes; llvm::DenseMap> CanonicalSpecializedAccessorsForGenericTypes; /// The queue of specialized generic types whose prespecialized metadata to /// emit. - llvm::SmallVector LazySpecializedTypeMetadataRecords; + llvm::SmallVector, 4> + LazySpecializedTypeMetadataRecords; /// The queue of metadata accessors to emit. /// @@ -423,11 +431,16 @@ class IRGenerator { void ensureRelativeSymbolCollocation(SILDefaultWitnessTable &wt); - llvm::SmallVector - canonicalSpecializationsForType(NominalTypeDecl *type) { - return CanonicalSpecializationsForGenericTypes.lookup(type); + llvm::SmallVector, 4> + metadataPrespecializationsForType(NominalTypeDecl *type) { + return MetadataPrespecializationsForGenericTypes.lookup(type); } + void + deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, + NominalTypeDecl &decl); + void noteUseOfMetadataAccessor(NominalTypeDecl *decl) { if (LazyMetadataAccessors.count(decl) == 0) { LazyMetadataAccessors.insert(decl); @@ -438,7 +451,8 @@ class IRGenerator { noteUseOfTypeGlobals(type, true, RequireMetadata); } - void noteUseOfSpecializedGenericTypeMetadata(CanType type); + void noteUseOfSpecializedGenericTypeMetadata( + IRGenModule &IGM, CanType theType, TypeMetadataCanonicality canonicality); void noteUseOfCanonicalSpecializedMetadataAccessor(CanType forType); void noteUseOfTypeMetadata(CanType type) { @@ -547,11 +561,6 @@ enum class MangledTypeRefRole { DefaultAssociatedTypeWitness, }; -enum class TypeMetadataCanonicality : bool { - Noncanonical, - Canonical, -}; - /// IRGenModule - Primary class for emitting IR for global declarations. /// class IRGenModule { diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 5a794512e3ff1..0a84464fd7663 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -45,6 +45,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" #include @@ -2040,8 +2041,12 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( GenericArguments &genericArgs, std::function valueAtIndex) { auto &IGM = IGF.IGM; - auto specializations = IGF.IGM.IRGen.canonicalSpecializationsForType(nominal); - if (specializations.size() > 0) { + auto specializations = IGM.IRGen.metadataPrespecializationsForType(nominal); + auto canonicalCount = llvm::count_if(specializations, [](auto pair) { + return pair.second == TypeMetadataCanonicality::Canonical; + }); + + if (canonicalCount > 0) { SmallVector conditionBlocks; for (size_t index = 0; index < specializations.size(); ++index) { conditionBlocks.push_back(llvm::BasicBlock::Create(IGM.getLLVMContext())); @@ -2057,7 +2062,11 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( specializationBlocks; auto switchDestination = llvm::BasicBlock::Create(IGM.getLLVMContext()); unsigned long blockIndex = 0; - for (auto specialization : specializations) { + for (auto pair : specializations) { + if (pair.second != TypeMetadataCanonicality::Canonical) { + continue; + } + auto specialization = pair.first; auto conditionBlock = conditionBlocks[blockIndex]; IGF.Builder.emitBlock(conditionBlock); auto successorBlock = blockIndex < conditionBlocks.size() - 1 @@ -2069,7 +2078,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( llvm::Value *condition = llvm::ConstantInt::get(IGM.Int1Ty, 1); auto nominal = specialization->getAnyNominal(); - auto requirements = GenericTypeRequirements(IGF.IGM, nominal); + auto requirements = GenericTypeRequirements(IGM, nominal); int requirementIndex = 0; for (auto requirement : requirements.getRequirements()) { auto parameter = requirement.TypeParameter; @@ -2090,7 +2099,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( RootProtocolConformance *rootConformance = concreteConformance->getRootConformance(); llvm::Value *expectedDescriptor = - IGF.IGM.getAddrOfProtocolConformanceDescriptor(rootConformance); + IGM.getAddrOfProtocolConformanceDescriptor(rootConformance); auto *witnessTable = valueAtIndex(requirementIndex); auto *witnessBuffer = IGF.Builder.CreateBitCast(witnessTable, IGM.Int8PtrPtrTy); @@ -2102,7 +2111,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( // Auth the stored descriptor. auto storedScheme = - IGF.IGM.getOptions().PointerAuth.ProtocolConformanceDescriptors; + IGM.getOptions().PointerAuth.ProtocolConformanceDescriptors; if (storedScheme) { auto authInfo = PointerAuthInfo::emit( IGF, storedScheme, witnessTable, @@ -2113,7 +2122,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( // Sign the descriptors. auto argScheme = - IGF.IGM.getOptions() + IGM.getOptions() .PointerAuth.ProtocolConformanceDescriptorsAsArguments; if (argScheme) { auto authInfo = PointerAuthInfo::emit( @@ -2127,10 +2136,10 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( } auto *call = IGF.Builder.CreateCall( - IGF.IGM.getCompareProtocolConformanceDescriptorsFn(), + IGM.getCompareProtocolConformanceDescriptorsFn(), {providedDescriptor, expectedDescriptor}); call->setDoesNotThrow(); - call->setCallingConv(IGF.IGM.SwiftCC); + call->setCallingConv(IGM.SwiftCC); call->addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::ReadNone); condition = IGF.Builder.CreateAnd(condition, call); @@ -2153,7 +2162,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( llvm::Value *specializedMetadata; if (isa(nominal)) { llvm::Function *accessor = - IGF.IGM + IGM .getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction( specialization, NotForDefinition); diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift index 62294db3ba1c6..9e7d63dcd6af4 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift @@ -9,6 +9,33 @@ // UNSUPPORTED: CPU=armv7s && OS=ios // CHECK-NOT: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = +// CHECK: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s7Generic11OneArgumentVy0C07IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s7Generic11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +47,31 @@ import Generic import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s7Generic11OneArgumentVy0C07IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s7Generic11OneArgumentVy0C07IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s7Generic11OneArgumentVy0C07IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift index acb5c56c5b943..2e99516a2171d 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift @@ -7,7 +7,33 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03OneA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03OneA0VyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03OneA0VyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03OneA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +44,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03OneA0VyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03OneA0VyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03OneA0VyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift index 2718c56287e14..01fd6ddbbe2e0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift @@ -7,7 +7,35 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03OneA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03OneA0VyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i8**, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03OneA0VyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03OneA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i8** @"$s8Argument7IntegerVAA1PAAWP", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +46,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03OneA0VyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03OneA0VyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03OneA0VyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift index 1cb2721fcc829..ef6073aa7b01c 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift @@ -8,7 +8,35 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMN" = +// CHECK: @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i8**, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME:}> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s6Module11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s6Module7IntegerVN", +// CHECK-SAME: i8** @"$s6Module7IntegerVAA1P8ArgumentWP", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME:}>, +// CHECK-SAME:align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +48,31 @@ import Module import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s6Module11OneArgumentVyAA7IntegerVAeA1P0C0yHCg_GMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift index ed8be0746ef1c..6991186ef1aae 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift @@ -7,7 +7,35 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03OneA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03OneA0VyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i8**, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03OneA0VyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03OneA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i8** @"$s8Argument7IntegerVAA1PAAWP", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +46,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03OneA0VyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03OneA0VyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03OneA0VyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift index bf23059dbf86f..3e2bd95dc0601 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift @@ -8,7 +8,43 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMN" = +// CHECK: @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// : [ +// : 4 x i8 +// : ], +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s6Module11TwoArgumentVyAA7IntegerV0C0ADVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s6Module11TwoArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s6Module7IntegerVN", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i32 {{8|16}}, +// : [ +// : 4 x i8 +// : ] zeroinitializer, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +56,31 @@ import Module import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s6Module11TwoArgumentVyAA7IntegerV0C0ADVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( TwoArgument(Module.Integer(13), Argument.Integer(17)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift index b751ee9562f7e..cd9fe461106bf 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift @@ -7,7 +7,43 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s8Argument03TwoA0VyAA7IntegerVGMN" = +// CHECK: @"$s8Argument03TwoA0VyAA7IntegerVAEGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// : [ +// : 4 x i8 +// : ], +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s8Argument03TwoA0VyAA7IntegerVAEGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s8Argument03TwoA0VMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i32 {{8|16}}, +// : [ +// : 4 x i8 +// : ] zeroinitializer, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +54,31 @@ func consume(_ t: T) { import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s8Argument03TwoA0VyAA7IntegerVAEGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s8Argument03TwoA0VyAA7IntegerVAEGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s8Argument03TwoA0VyAA7IntegerVAEGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( TwoArgument(Integer(13), Integer(17)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift index cf8a51c1899c2..d89d0e0766170 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift @@ -8,7 +8,33 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = +// CHECK: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s7Generic11OneArgumentVy0C07IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s7Generic11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s8Argument7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -20,8 +46,31 @@ import Generic import Argument // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s7Generic11OneArgumentVy0C07IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s7Generic11OneArgumentVy0C07IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s7Generic11OneArgumentVy0C07IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift index c7f22edd10d3d..5953b4c083fd1 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift @@ -7,7 +7,33 @@ // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s7Generic11OneArgumentVyAA7IntegerVGMN" = +// CHECK: @"$s7Generic11OneArgumentVyAA7IntegerVGMN" = linkonce_odr hidden constant <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }> <{ +// : i8** getelementptr inbounds ( +// : %swift.vwtable, +// : %swift.vwtable* @" +// CHECK-SAME: $s7Generic11OneArgumentVyAA7IntegerVGWV +// : ", +// : i32 0, +// : i32 0 +// : ), +// CHECK-SAME: [[INT]] 512, +// : %swift.type_descriptor* @" +// CHECK-SAME: $s7Generic11OneArgumentVMn +// : ", +// CHECK-SAME: %swift.type* @"$s7Generic7IntegerVN", +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 {{4|8}}, +// CHECK-SAME: i64 1 +// CHECK-SAME: }>, +// CHECK-SAME: align [[ALIGNMENT]] @inline(never) func consume(_ t: T) { @@ -18,8 +44,31 @@ func consume(_ t: T) { import Generic // CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} { -// CHECK: [[METADATA:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s7Generic11OneArgumentVyAA7IntegerVGMD") -// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture {{%[0-9]+}}, %swift.type* [[METADATA]]) +// CHECK: [[CANONICALIZED_METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @swift_getCanonicalSpecializedMetadata( +// CHECK-SAME: [[INT]] 0, +// CHECK-SAME: %swift.type* getelementptr inbounds ( +// CHECK-SAME: %swift.full_type, +// CHECK-SAME: %swift.full_type* bitcast ( +// CHECK-SAME: <{ +// CHECK-SAME: i8**, +// CHECK-SAME: [[INT]], +// CHECK-SAME: %swift.type_descriptor*, +// CHECK-SAME: %swift.type*, +// CHECK-SAME: i32, +// CHECK-SAME: i32, +// CHECK-SAME: i64 +// CHECK-SAME: }>* @"$s7Generic11OneArgumentVyAA7IntegerVGMN" to %swift.full_type* +// CHECK-SAME: ), +// CHECK-SAME: i32 0, +// CHECK-SAME: i32 1 +// CHECK-SAME: ), +// CHECK-SAME: %swift.type** @"$s7Generic11OneArgumentVyAA7IntegerVGMJ" +// CHECK-SAME: ) +// CHECK-NEXT: [[CANONICALIZED_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[CANONICALIZED_METADATA_RESPONSE]], 0 +// CHECK-NEXT: call swiftcc void @"$s4main7consumeyyxlF"( +// CHECK-SAME: %swift.opaque* noalias nocapture {{%[0-9]+}}, +// CHECK-SAME: %swift.type* [[CANONICALIZED_METADATA]] +// CHECK-SAME: ) // CHECK: } func doit() { consume( OneArgument(Integer(13)) ) From b1408028a79a271a257348b92786e6345adec74c Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 13 Aug 2020 17:38:17 -0700 Subject: [PATCH 136/663] [metadata prespecialization] Allow more noncanonical records. Previously, noncanonical records were only allowed if one of the arguments was from the module where the record was to be emitted. Here, that restriction is lifted. Now getSpecializedGenericMetadata will, on first run, register all canonical metadata with the global cache before attempting to bless the passed-in noncanonical record, allowing noncanonical records to be for the same arguments as a canonical record (since in the case that a canonical record does exist, it will be returned). --- lib/IRGen/MetadataRequest.cpp | 50 ------------------------------ stdlib/public/runtime/Metadata.cpp | 28 +++++++++++++++-- 2 files changed, 25 insertions(+), 53 deletions(-) diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 0a84464fd7663..17235dfa35afb 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -846,57 +846,7 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable( return !isGenericWithoutPrespecializedConformance() && metadataAccessIsTrivial() && witnessTablesAreReferenceable(); }); - auto anyArgumentIsFromCurrentModule = - llvm::any_of(environment->getGenericParams(), [&](auto parameter) { - auto signature = environment->getGenericSignature(); - const auto protocols = signature->getRequiredProtocols(parameter); - auto argument = ((Type *)parameter)->subst(substitutions); - auto canonicalType = argument->getCanonicalType(); - - auto argumentIsFromCurrentModule = [&]() { - if (auto *argumentNominal = argument->getAnyNominal()) { - return IGM.getSwiftModule() == argumentNominal->getModuleContext(); - } - return false; - }; - auto anyConformanceIsFromCurrentModule = [&]() { - return llvm::any_of(protocols, [&](ProtocolDecl *protocol) { - auto conformance = - signature->lookupConformance(canonicalType, protocol); - if (!conformance.isConcrete()) { - return false; - } - auto rootConformance = - conformance.getConcrete()->getRootConformance(); - return IGM.getSwiftModule() == - rootConformance->getDeclContext()->getParentModule(); - }); - }; - - return argumentIsFromCurrentModule() || - anyConformanceIsFromCurrentModule(); - }); return allArgumentsAreStaticallyAddressable && - // A type's metadata cannot be prespecialized non-canonically if it - // could be specialized canonically. The reasons for that: - // (1) Canonically prespecialized metadata is not registered with the - // runtime; at runtime, whether canonically prespecialized - // metadata exists can only be determined by calling the metadata - // accessor. - // (2) At compile time, there is no way to determine whether the - // defining module has prespecialized metadata at a particular - // argument list. - // (3) Subsequent versions of the defining module may add or remove - // prespecialized metadata. - // - // To account for that, we only allow non-canonical prespecialization - // when at least one of the arguments is from the current module - // where non-canonical prespecialization might occur. Consequently, - // some prespecialization opportunities may be missed (such as when - // an argument comes from a module which it is known the defining - // module does not depend on). - !((canonicality == NoncanonicalSpecializedMetadata) && - !anyArgumentIsFromCurrentModule) && IGM.getTypeInfoForUnlowered(type).isFixedSize( ResilienceExpansion::Maximal); } diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index a756dc847d56d..34f4bc71a8252 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -720,15 +720,37 @@ MetadataResponse swift::swift_getCanonicalSpecializedMetadata( auto &cache = getCache(*description); assert(description->getFullGenericContextHeader().Base.NumKeyArguments == cache.NumKeyParameters + cache.NumWitnessTables); + if (auto *classDescription = dyn_cast(description)) { + auto canonicalMetadataAccessors = classDescription->getCanonicalMetadataPrespecializationAccessors(); + for (auto &canonicalMetadataAccessorPtr : canonicalMetadataAccessors) { + auto *canonicalMetadataAccessor = canonicalMetadataAccessorPtr.get(); + auto response = canonicalMetadataAccessor(request); + auto *canonicalMetadata = response.Value; + const void *const *arguments = + reinterpret_cast(canonicalMetadata->getGenericArgs()); + auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + arguments); + auto result = cache.getOrInsert(key, MetadataRequest(MetadataState::Complete, /*isNonBlocking*/true), canonicalMetadata); + assert(result.second.Value == canonicalMetadata); + } + } else { + auto canonicalMetadatas = description->getCanonicicalMetadataPrespecializations(); + for (auto &canonicalMetadataPtr : canonicalMetadatas) { + Metadata *canonicalMetadata = canonicalMetadataPtr.get(); + const void *const *arguments = + reinterpret_cast(canonicalMetadata->getGenericArgs()); + auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + arguments); + auto result = cache.getOrInsert(key, MetadataRequest(MetadataState::Complete, /*isNonBlocking*/true), canonicalMetadata); + assert(result.second.Value == canonicalMetadata); + } + } const void *const *arguments = reinterpret_cast(candidate->getGenericArgs()); auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, arguments); auto result = cache.getOrInsert(key, request, candidate); - assert( - !result.second.Value->isCanonicalStaticallySpecializedGenericMetadata()); - cachedMetadataAddr->store(result.second.Value, std::memory_order_release); return result.second; From 11d801de517889d7d241aa692846f8f86996a22a Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 13 Aug 2020 21:09:06 -0700 Subject: [PATCH 137/663] [Concurrency] Add @asyncHandler attribute. An asynchronous handler behaves externally like a synchronous function, but internally it is handled like an asynchronous function, meaning that it can execute operations with suspension points such as calling other async functions. The body of the function is executed just as if it and its caller were async functions, except that the caller is resumed when the callee reaches its first suspension point rather than only when the callee exits. --- include/swift/AST/Attr.def | 5 ++ include/swift/AST/DiagnosticsSema.def | 22 +++++++++ lib/Sema/TypeCheckAttr.cpp | 53 ++++++++++++++++++++++ lib/Sema/TypeCheckDeclOverride.cpp | 1 + test/attr/asynchandler.swift | 30 ++++++++++++ test/attr/asynchandler_noconcurrency.swift | 4 ++ 6 files changed, 115 insertions(+) create mode 100644 test/attr/asynchandler.swift create mode 100644 test/attr/asynchandler_noconcurrency.swift diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index b6fea6459d533..605190cf62a48 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -560,6 +560,11 @@ SIMPLE_DECL_ATTR(noDerivative, NoDerivative, ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove, 100) +SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler, + OnFunc | UserInaccessible | + ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | + NotSerialized, 101) + #undef TYPE_ATTR #undef DECL_ATTR_ALIAS #undef CONTEXTUAL_DECL_ATTR_ALIAS diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 52293cc6989ac..d57cb7c6ab2af 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4074,6 +4074,28 @@ NOTE(protocol_witness_async_conflict,none, ERROR(async_autoclosure_nonasync_function,none, "'async' autoclosure parameter in a non-'async' function", ()) +ERROR(asynchandler_attr_requires_concurrency,none, + "'@asyncHandler' is only valid when experimental concurrency is enabled", + ()) +ERROR(asynchandler_non_func,none, + "'@asyncHandler' can only be applied to functions", + ()) +ERROR(asynchandler_returns_value,none, + "'@asyncHandler' function can only return 'Void'", + ()) +ERROR(asynchandler_throws,none, + "'@asyncHandler' function cannot throw", + ()) +ERROR(asynchandler_async,none, + "'@asyncHandler' function cannot be 'async' itself", + ()) +ERROR(asynchandler_inout_parameter,none, + "'inout' parameter is not allowed in '@asyncHandler' function", + ()) +ERROR(asynchandler_mutating,none, + "'@asyncHandler' function cannot be 'mutating'", + ()) + //------------------------------------------------------------------------------ // MARK: Type Check Types //------------------------------------------------------------------------------ diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 1133d4eb3199b..a0e76a5e0cd3f 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -257,6 +257,59 @@ class AttributeChecker : public AttributeVisitor { void visitDifferentiableAttr(DifferentiableAttr *attr); void visitDerivativeAttr(DerivativeAttr *attr); void visitTransposeAttr(TransposeAttr *attr); + + void visitAsyncHandlerAttr(AsyncHandlerAttr *attr) { + if (!Ctx.LangOpts.EnableExperimentalConcurrency) { + diagnoseAndRemoveAttr(attr, diag::asynchandler_attr_requires_concurrency); + return; + } + + auto func = dyn_cast(D); + if (!func) { + diagnoseAndRemoveAttr(attr, diag::asynchandler_non_func); + return; + } + + if (!func->getResultInterfaceType()->isVoid()) { + func->diagnose(diag::asynchandler_returns_value) + .highlight(func->getBodyResultTypeLoc().getSourceRange()); + attr->setInvalid(); + return; + } + + if (func->hasThrows()) { + func->diagnose(diag::asynchandler_throws) + .fixItRemove(func->getThrowsLoc()); + attr->setInvalid(); + return; + } + + if (func->hasAsync()) { + func->diagnose(diag::asynchandler_async) + .fixItRemove(func->getAsyncLoc()); + attr->setInvalid(); + return; + } + + for (auto param : *func->getParameters()) { + if (param->isInOut()) { + param->diagnose(diag::asynchandler_inout_parameter) + .fixItRemove(param->getSpecifierLoc()); + attr->setInvalid(); + return; + } + } + + if (func->isMutating()) { + auto diag = Ctx.Diags.diagnose(func, diag::asynchandler_mutating); + diag.highlight(attr->getRangeWithAt()); + if (auto mutatingAttr = func->getAttrs().getAttribute()) { + diag.fixItRemove(mutatingAttr->getRange()); + } + attr->setInvalid(); + return; + } + } }; } // end anonymous namespace diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 9be81b3cdb722..564e7b9ba4481 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1416,6 +1416,7 @@ namespace { UNINTERESTING_ATTR(AccessControl) UNINTERESTING_ATTR(Alignment) UNINTERESTING_ATTR(AlwaysEmitIntoClient) + UNINTERESTING_ATTR(AsyncHandler) UNINTERESTING_ATTR(Borrowed) UNINTERESTING_ATTR(CDecl) UNINTERESTING_ATTR(Consuming) diff --git a/test/attr/asynchandler.swift b/test/attr/asynchandler.swift new file mode 100644 index 0000000000000..1a91f550bb5b1 --- /dev/null +++ b/test/attr/asynchandler.swift @@ -0,0 +1,30 @@ +// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency + +@asyncHandler func asyncHandler1() { } + +@asyncHandler +func asyncHandlerBad1() -> Int { 0 } +// expected-error@-1{{'@asyncHandler' function can only return 'Void'}} + +@asyncHandler +func asyncHandlerBad2() async { } +// expected-error@-1{{'@asyncHandler' function cannot be 'async' itself}}{{25-31=}} + +@asyncHandler +func asyncHandlerBad3() throws { } +// expected-error@-1{{'@asyncHandler' function cannot throw}}{{25-32=}} + +@asyncHandler +func asyncHandlerBad4(result: inout Int) { } +// expected-error@-1{{'inout' parameter is not allowed in '@asyncHandler' function}} + +struct X { + @asyncHandler func asyncHandlerMethod() { } + + @asyncHandler + mutating func asyncHandlerMethodBad1() { } + // expected-error@-1{{'@asyncHandler' function cannot be 'mutating'}}{{3-12=}} + + @asyncHandler init() { } + // expected-error@-1{{@asyncHandler may only be used on 'func' declarations}} +} diff --git a/test/attr/asynchandler_noconcurrency.swift b/test/attr/asynchandler_noconcurrency.swift new file mode 100644 index 0000000000000..97545fd0bc555 --- /dev/null +++ b/test/attr/asynchandler_noconcurrency.swift @@ -0,0 +1,4 @@ +// RUN: %target-swift-frontend -typecheck -verify %s + +@asyncHandler func asyncHandler1() { } +// expected-error@-1{{'@asyncHandler' is only valid when experimental concurrency is enabled}} From 6ed662ec1715eba50dd3eaa5160d09aac200d81d Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 13 Aug 2020 21:38:39 -0700 Subject: [PATCH 138/663] [Concurrency] @asyncHandler functions are an async context. Allow async calls and await expressions within @asyncHandler functions. If we see an async call or await expression in a function that is not an async context, also suggest adding @asyncHandler if the function meets the semantic constraints. --- include/swift/AST/Decl.h | 7 ++ include/swift/AST/DiagnosticsSema.def | 4 +- lib/Sema/TypeCheckAttr.cpp | 107 +++++++++++++++++--------- lib/Sema/TypeCheckDecl.cpp | 7 +- lib/Sema/TypeCheckEffects.cpp | 4 +- lib/Sema/TypeChecker.h | 4 + test/attr/asynchandler.swift | 11 ++- test/expr/unary/async_await.swift | 7 +- 8 files changed, 104 insertions(+), 47 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 0d690d1db3f92..5aa4d9c2974d1 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5888,6 +5888,13 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// type of the function will be `async` as well. bool hasAsync() const { return Bits.AbstractFunctionDecl.Async; } + /// Returns true if the function is a suitable 'async' context. + /// + /// Functions that are an 'async' context can make calls to 'async' functions. + bool isAsyncContext() const { + return hasAsync() || getAttrs().hasAttribute(); + } + /// Returns true if the function body throws. bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; } diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d57cb7c6ab2af..abc49a1d3a5a7 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4047,7 +4047,7 @@ WARNING(no_throw_in_do_with_catch,none, ERROR(async_call_without_await,none, "call is 'async' but is not marked with 'await'", ()) ERROR(async_call_without_await_in_autoclosure,none, - "call is 'async' in an autoclosure argument is not marked with 'await'", ()) + "call is 'async' in an autoclosure argument that is not marked with 'await'", ()) WARNING(no_async_in_await,none, "no calls to 'async' functions occur within 'await' expression", ()) ERROR(async_call_in_illegal_context,none, @@ -4064,6 +4064,8 @@ ERROR(async_in_nonasync_function,none, (bool, bool)) NOTE(note_add_async_to_function,none, "add 'async' to function %0 to make it asynchronous", (DeclName)) +NOTE(note_add_asynchandler_to_function,none, + "add '@asyncHandler' to function %0 to create an implicit asynchronous context", (DeclName)) ERROR(not_objc_function_async,none, "'async' function cannot be represented in Objective-C", ()) NOTE(not_objc_function_type_async,none, diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index a0e76a5e0cd3f..0e047c9c3e4d7 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -41,6 +41,66 @@ using namespace swift; +/// Check whether the @asyncHandler attribute can be applied to the given +/// function declaration. +/// +/// \param diagnose Whether to emit a diagnostic when a problem is encountered. +/// +/// \returns \c true if there was a problem with adding the attribute, \c false +/// otherwise. +static bool checkAsyncHandler(FuncDecl *func, bool diagnose) { + if (!func->getResultInterfaceType()->isVoid()) { + if (diagnose) { + func->diagnose(diag::asynchandler_returns_value) + .highlight(func->getBodyResultTypeLoc().getSourceRange()); + } + + return true; + } + + if (func->hasThrows()) { + if (diagnose) { + func->diagnose(diag::asynchandler_throws) + .fixItRemove(func->getThrowsLoc()); + } + + return true; + } + + if (func->hasAsync()) { + if (diagnose) { + func->diagnose(diag::asynchandler_async) + .fixItRemove(func->getAsyncLoc()); + } + + return true; + } + + for (auto param : *func->getParameters()) { + if (param->isInOut()) { + if (diagnose) { + param->diagnose(diag::asynchandler_inout_parameter) + .fixItRemove(param->getSpecifierLoc()); + } + + return true; + } + } + + if (func->isMutating()) { + if (diagnose) { + auto diag = func->diagnose(diag::asynchandler_mutating); + if (auto mutatingAttr = func->getAttrs().getAttribute()) { + diag.fixItRemove(mutatingAttr->getRange()); + } + } + + return true; + } + + return false; +} + namespace { /// This emits a diagnostic with a fixit to remove the attribute. template @@ -270,42 +330,7 @@ class AttributeChecker : public AttributeVisitor { return; } - if (!func->getResultInterfaceType()->isVoid()) { - func->diagnose(diag::asynchandler_returns_value) - .highlight(func->getBodyResultTypeLoc().getSourceRange()); - attr->setInvalid(); - return; - } - - if (func->hasThrows()) { - func->diagnose(diag::asynchandler_throws) - .fixItRemove(func->getThrowsLoc()); - attr->setInvalid(); - return; - } - - if (func->hasAsync()) { - func->diagnose(diag::asynchandler_async) - .fixItRemove(func->getAsyncLoc()); - attr->setInvalid(); - return; - } - - for (auto param : *func->getParameters()) { - if (param->isInOut()) { - param->diagnose(diag::asynchandler_inout_parameter) - .fixItRemove(param->getSpecifierLoc()); - attr->setInvalid(); - return; - } - } - - if (func->isMutating()) { - auto diag = Ctx.Diags.diagnose(func, diag::asynchandler_mutating); - diag.highlight(attr->getRangeWithAt()); - if (auto mutatingAttr = func->getAttrs().getAttribute()) { - diag.fixItRemove(mutatingAttr->getRange()); - } + if (checkAsyncHandler(func, /*diagnose=*/true)) { attr->setInvalid(); return; } @@ -5201,3 +5226,13 @@ void AttributeChecker::visitTransposeAttr(TransposeAttr *attr) { // Set the resolved linearity parameter indices in the attribute. attr->setParameterIndices(linearParamIndices); } + +void swift::addAsyncNotes(FuncDecl *func) { + func->diagnose(diag::note_add_async_to_function, func->getName()); + + if (!checkAsyncHandler(func, /*diagnose=*/false)) { + func->diagnose( + diag::note_add_asynchandler_to_function, func->getName()) + .fixItInsert(func->getAttributeInsertionLoc(false), "@asyncHandler "); + } +} diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index cf6c3e3864d99..9c70eafb6b891 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2155,11 +2155,10 @@ static Type validateParameterType(ParamDecl *decl) { if (auto fnType = Ty->getAs()) { if (fnType->isAsync() && !(isa(dc) && - cast(dc)->hasAsync())) { + cast(dc)->isAsyncContext())) { decl->diagnose(diag::async_autoclosure_nonasync_function); - if (auto func = dyn_cast(dc)) { - func->diagnose(diag::note_add_async_to_function, func->getName()); - } + if (auto func = dyn_cast(dc)) + addAsyncNotes(func); } } } diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 7de3d6c5a8dc2..4c595ca7f9eba 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -932,7 +932,7 @@ class Context { } } - return Context(D->hasThrows(), D->hasAsync(), AnyFunctionRef(D)); + return Context(D->hasThrows(), D->isAsyncContext(), AnyFunctionRef(D)); } static Context forDeferBody() { @@ -1254,7 +1254,7 @@ class Context { if (!func) return; - func->diagnose(diag::note_add_async_to_function, func->getName()); + addAsyncNotes(func); } void diagnoseUnhandledAsyncSite(DiagnosticEngine &Diags, ASTNode node) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index f551fda552249..e053cd664fdfc 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1391,6 +1391,10 @@ void checkUnknownAttrRestrictions( /// it to later stages. void bindSwitchCasePatternVars(DeclContext *dc, CaseStmt *stmt); +/// Add notes suggesting the addition of 'async' or '@asyncHandler', as +/// appropriate, to a diagnostic for a function that isn't an async context. +void addAsyncNotes(FuncDecl *func); + } // end namespace swift #endif diff --git a/test/attr/asynchandler.swift b/test/attr/asynchandler.swift index 1a91f550bb5b1..82e208206e3f4 100644 --- a/test/attr/asynchandler.swift +++ b/test/attr/asynchandler.swift @@ -1,6 +1,15 @@ // RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency -@asyncHandler func asyncHandler1() { } +func globalAsyncFunction() async -> Int { 0 } + +@asyncHandler func asyncHandler1() { + // okay, it's an async context + let _ = await globalAsyncFunction() +} + +@asyncHandler func asyncHandler2(fn: @autoclosure () async -> Int ) { + // okay, it's an async context +} @asyncHandler func asyncHandlerBad1() -> Int { 0 } diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index 71ed441070442..3601108f8e90c 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -21,6 +21,7 @@ func test2( } func test3() { // expected-note{{add 'async' to function 'test3()' to make it asynchronous}} + // expected-note@-1{{add '@asyncHandler' to function 'test3()' to create an implicit asynchronous context}}{{1-1=@asyncHandler }} _ = await getInt() // expected-error{{'async' in a function that does not support concurrency}} } @@ -36,7 +37,7 @@ struct SomeStruct { func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { } func acceptAutoclosureAsync(_: @autoclosure () async -> Int) async { } -func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) { } +func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) -> Int { 0 } // expected-error@-1{{'async' autoclosure parameter in a non-'async' function}} // expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}} @@ -46,13 +47,13 @@ struct HasAsyncBad { } func testAutoclosure() async { - await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} + await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument that is not marked with 'await'}} await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} await acceptAutoclosureAsync(await getInt()) await acceptAutoclosureNonAsync(await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} - await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}} + await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument that is not marked with 'await'}} await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}} } From 8cd892aba8edaf1c4155430186e4843926e14f57 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 13 Aug 2020 21:44:20 -0700 Subject: [PATCH 139/663] [Concurrency] Serialize @asyncHandler attribute. We'll be able to infer @asyncHandler attributes from protocol requirements, which means we'll need to serialize this information. --- include/swift/AST/Attr.def | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 605190cf62a48..660128379a139 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -562,8 +562,8 @@ SIMPLE_DECL_ATTR(noDerivative, NoDerivative, SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler, OnFunc | UserInaccessible | - ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | - NotSerialized, 101) + ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, + 101) #undef TYPE_ATTR #undef DECL_ATTR_ALIAS From e54127b15214c30a15de2775826b5b48e349d89d Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Thu, 13 Aug 2020 21:55:44 -0700 Subject: [PATCH 140/663] Clean up the whitespace in build-script --- utils/build-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/build-script b/utils/build-script index 44819a859feac..fb87c118b017a 100755 --- a/utils/build-script +++ b/utils/build-script @@ -996,7 +996,7 @@ class BuildScriptInvocation(object): for host_target in all_hosts: for product_class in impl_product_classes: self._execute_install_action(host_target, product_class) - + # Lipo... self._execute_merged_host_lipo_action() From 6a8f0cfbc130056d2eea6158d3ed982443972078 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 12 Aug 2020 18:32:48 -0300 Subject: [PATCH 141/663] Fix reading elf section from file buffer (cherry picked from commit d2e162676d9a69f4a175b09bee46e3450e5c86b8) --- include/swift/Reflection/ReflectionContext.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index c3818f477eaf6..0ff6c8b44436f 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -479,12 +479,12 @@ class ReflectionContext for (const typename T::Section *Hdr : SecHdrVec) { uint32_t Offset = Hdr->sh_name; const char *Start = (const char *)StrTab + Offset; - uint64_t Size = strnlen(Start, StrTabSize - Offset); - if (Size > StrTabSize - Offset) { + uint64_t StringSize = strnlen(Start, StrTabSize - Offset); + if (StringSize > StrTabSize - Offset) { Error = true; break; } - std::string SecName(Start, Size); + std::string SecName(Start, StringSize); if (SecName != Name) continue; RemoteAddress SecStart = @@ -495,7 +495,7 @@ class ReflectionContext // sh_offset gives us the offset to the section in the file, // while sh_addr gives us the offset in the process. auto Offset = Hdr->sh_offset; - if (FileBuffer->allocatedSize() > Offset + Size) { + if (FileBuffer->allocatedSize() < Offset + SecSize) { Error = true; break; } @@ -503,7 +503,8 @@ class ReflectionContext SecBuf = MemoryReader::ReadBytesResult( Buf, [](const void *ptr) { free(const_cast(ptr)); }); memcpy((void *)Buf, - (const void *)((uint64_t)FileBuffer->base() + Offset), Size); + (const void *)((uint64_t)FileBuffer->base() + Offset), + SecSize); } else { SecBuf = this->getReader().readBytes(SecStart, SecSize); } From 8fa18a42b8acce46e718e5891f2c96fa72827311 Mon Sep 17 00:00:00 2001 From: Marcel Hlopko Date: Fri, 14 Aug 2020 16:42:15 +0200 Subject: [PATCH 142/663] Remove -Xcc -std=c++17 (#33449) --- test/Interop/Cxx/reference/reference.swift | 2 +- test/Interop/Cxx/static/constexpr-static-member-var.swift | 2 +- test/Interop/Cxx/static/inline-static-member-var.swift | 2 +- test/Interop/Cxx/static/static-var.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Interop/Cxx/reference/reference.swift b/test/Interop/Cxx/reference/reference.swift index 71d211b04761c..278f06a23281e 100644 --- a/test/Interop/Cxx/reference/reference.swift +++ b/test/Interop/Cxx/reference/reference.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/reference.cpp -I %S/Inputs -o %t/reference.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/reference %t/reference.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/reference %t/reference.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/reference // RUN: %target-run %t/reference // diff --git a/test/Interop/Cxx/static/constexpr-static-member-var.swift b/test/Interop/Cxx/static/constexpr-static-member-var.swift index e40cddf397282..77f15f321666f 100644 --- a/test/Interop/Cxx/static/constexpr-static-member-var.swift +++ b/test/Interop/Cxx/static/constexpr-static-member-var.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/static-member-var.cpp -I %S/Inputs -o %t/static-member-var.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/statics // RUN: %target-run %t/statics // diff --git a/test/Interop/Cxx/static/inline-static-member-var.swift b/test/Interop/Cxx/static/inline-static-member-var.swift index 76e7a1d9b09f0..052f362840329 100644 --- a/test/Interop/Cxx/static/inline-static-member-var.swift +++ b/test/Interop/Cxx/static/inline-static-member-var.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/inline-static-member-var.cpp -I %S/Inputs -o %t/inline-static-member-var.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/inline-static-member-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/inline-static-member-var.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/statics // RUN: %target-run %t/statics 2&>1 // diff --git a/test/Interop/Cxx/static/static-var.swift b/test/Interop/Cxx/static/static-var.swift index 0528af17f35a2..9b66cadf22501 100644 --- a/test/Interop/Cxx/static/static-var.swift +++ b/test/Interop/Cxx/static/static-var.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang -c %S/Inputs/static-var.cpp -I %S/Inputs -o %t/static-var.o -std=c++17 -// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++17 +// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-var.o -Xfrontend -enable-cxx-interop // RUN: %target-codesign %t/statics // RUN: %target-run %t/statics // From aa5195aa89d956b2581110a573950d8e8f481677 Mon Sep 17 00:00:00 2001 From: Zoe Carver Date: Fri, 14 Aug 2020 09:28:15 -0700 Subject: [PATCH 143/663] Remove unneeded CHECK in type-classification-non-trivial-irgen. (#33474) This CHECK line didn't use an alias, so it caused the CI to fail. It turns out the CHECK line isn't actually needed. --- .../Cxx/class/type-classification-non-trivial-irgen.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift index fcbf32cff73d5..c0a48574a1493 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift @@ -29,7 +29,6 @@ public func testStructWithCopyConstructorAndValue() -> Bool { // CHECK: [[MEMBER_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 // CHECK: [[MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_ELEMENT]], i32 0, i32 0 // CHECK: store i32 42, i32* [[MEMBER_VALUE]] -// CHECK: %obj.member = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 // CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VALUE]] From f523c8875459d6cd950fdbfefc6ab593ced876c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Fri, 14 Aug 2020 09:50:31 -0700 Subject: [PATCH 144/663] [Serialization] Serialize the isUserAccessible bit on functions rdar://problem/53891642 SR-7460 --- lib/Serialization/Deserialization.cpp | 3 +++ lib/Serialization/ModuleFormat.h | 3 ++- lib/Serialization/Serialization.cpp | 1 + .../complete_user_accessibility_helper.swift | 3 +++ test/IDE/complete_user_accessible.swift | 19 +++++++++++++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 test/IDE/Inputs/complete_user_accessibility_helper.swift create mode 100644 test/IDE/complete_user_accessible.swift diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index ddbc8f9a513d0..b166b6c850529 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2995,6 +2995,7 @@ class DeclDeserializer { DeclID accessorStorageDeclID; bool overriddenAffectsABI, needsNewVTableEntry, isTransparent; DeclID opaqueReturnTypeID; + bool isUserAccessible; ArrayRef nameAndDependencyIDs; if (!isAccessor) { @@ -3012,6 +3013,7 @@ class DeclDeserializer { rawAccessLevel, needsNewVTableEntry, opaqueReturnTypeID, + isUserAccessible, nameAndDependencyIDs); } else { decls_block::AccessorLayout::readRecord(scratch, contextID, isImplicit, @@ -3196,6 +3198,7 @@ class DeclDeserializer { fn->setForcedStaticDispatch(hasForcedStaticDispatch); ctx.evaluator.cacheOutput(NeedsNewVTableEntryRequest{fn}, std::move(needsNewVTableEntry)); + fn->setUserAccessible(isUserAccessible); if (opaqueReturnTypeID) { ctx.evaluator.cacheOutput( diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 6c2cf423887f7..73bcf352de6b4 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 569; // subclass scope +const uint16_t SWIFTMODULE_VERSION_MINOR = 570; // isUserAccessible /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1307,6 +1307,7 @@ namespace decls_block { AccessLevelField, // access level BCFixed<1>, // requires a new vtable slot DeclIDField, // opaque result type decl + BCFixed<1>, // isUserAccessible? BCArray // name components, // followed by TypeID dependencies // The record is trailed by: diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8c5cd273a7e3b..3ffbba999073a 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3437,6 +3437,7 @@ class Serializer::DeclSerializer : public DeclVisitor { rawAccessLevel, fn->needsNewVTableEntry(), S.addDeclRef(fn->getOpaqueResultTypeDecl()), + fn->isUserAccessible(), nameComponentsAndDependencies); writeGenericParams(fn->getGenericParams()); diff --git a/test/IDE/Inputs/complete_user_accessibility_helper.swift b/test/IDE/Inputs/complete_user_accessibility_helper.swift new file mode 100644 index 0000000000000..0ff5d6c417bf9 --- /dev/null +++ b/test/IDE/Inputs/complete_user_accessibility_helper.swift @@ -0,0 +1,3 @@ +public enum MyEnum { + case foo, bar +} diff --git a/test/IDE/complete_user_accessible.swift b/test/IDE/complete_user_accessible.swift new file mode 100644 index 0000000000000..551648d195f31 --- /dev/null +++ b/test/IDE/complete_user_accessible.swift @@ -0,0 +1,19 @@ +/// Check that serialized non user accessible functions are not autocompleted. +/// rdar://problem/53891642 +/// SR-7460 + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module %S/Inputs/complete_user_accessibility_helper.swift -module-name helper -emit-module-path %t/helper.swiftmodule +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=USER-ACCESS -I %t | %FileCheck %s -check-prefix=USER-ACCESS + +import helper + +{ + _ = MyEnum.#^USER-ACCESS^# +// USER-ACCESS: Begin completions +// USER-ACCESS-DAG: Keyword[self]/CurrNominal: self[#MyEnum.Type#]; name=self +// USER-ACCESS-DAG: Keyword/CurrNominal: Type[#MyEnum.Type#]; name=Type +// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: foo[#MyEnum#]; name=foo +// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: bar[#MyEnum#]; name=bar +// USER-ACCESS-NOT: __derived_enum_equals +} From 22c157f159f654d551b6ef9cfe97294286929bbb Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 13 Aug 2020 19:01:16 -0700 Subject: [PATCH 145/663] [CodeCompletion] Parse #if block containing CC token as active rdar://problem/67027408 --- lib/Parse/ParseIfConfig.cpp | 28 ++++++++++- lib/Parse/Parser.cpp | 5 +- test/IDE/complete_in_ifconfig.swift | 75 +++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 test/IDE/complete_in_ifconfig.swift diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index a1c260f1e38bd..01732baf417f9 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -603,17 +603,33 @@ static Expr *findAnyLikelySimulatorEnvironmentTest(Expr *Condition) { /// Delegate callback function to parse elements in the blocks. ParserResult Parser::parseIfConfig( llvm::function_ref &, bool)> parseElements) { + assert(Tok.is(tok::pound_if)); SyntaxParsingContext IfConfigCtx(SyntaxContext, SyntaxKind::IfConfigDecl); SmallVector Clauses; Parser::StructureMarkerRAII ParsingDecl( *this, Tok.getLoc(), Parser::StructureMarkerKind::IfConfig); + // See if this '#if ... #endif' directive contains code completion token. + bool hasCCToken = false; + if (SourceMgr.hasCodeCompletionBuffer() && + SourceMgr.getCodeCompletionBufferID() == L->getBufferID()) { + BacktrackingScope backtrack(*this); + auto startLoc = Tok.getLoc(); + skipSingle(); + auto endLoc = PreviousLoc; + hasCCToken = SourceMgr.rangeContainsTokenLoc( + SourceRange(startLoc, endLoc), SourceMgr.getCodeCompletionLoc()); + } + bool shouldEvaluate = // Don't evaluate if it's in '-parse' mode, etc. shouldEvaluatePoundIfDecls() && // If it's in inactive #if ... #endif block, there's no point to do it. - !getScopeInfo().isInactiveConfigBlock(); + !getScopeInfo().isInactiveConfigBlock() && + // If this directive contains code completion, 'isActive' is determined + // solely by which block has the completion token. + !hasCCToken; bool foundActive = false; bool isVersionCondition = false; @@ -658,6 +674,16 @@ ParserResult Parser::parseIfConfig( } } + // Treat the region containing code completion token as "active". + if (hasCCToken && !foundActive) { + BacktrackingScope backtrack(*this); + auto startLoc = Tok.getLoc(); + skipUntilConditionalBlockClose(); + auto endLoc = PreviousLoc; + isActive = SourceMgr.rangeContainsTokenLoc( + SourceRange(startLoc, endLoc), SourceMgr.getCodeCompletionLoc()); + } + foundActive |= isActive; if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) { diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 601527fa7ba19..7b56a1f629368 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -695,8 +695,9 @@ void Parser::skipSingle() { void Parser::skipUntil(tok T1, tok T2) { // tok::NUM_TOKENS is a sentinel that means "don't skip". if (T1 == tok::NUM_TOKENS && T2 == tok::NUM_TOKENS) return; - - while (Tok.isNot(T1, T2, tok::eof, tok::pound_endif, tok::code_complete)) + + while (Tok.isNot(T1, T2, tok::eof, tok::pound_endif, tok::pound_else, + tok::pound_elseif)) skipSingle(); } diff --git a/test/IDE/complete_in_ifconfig.swift b/test/IDE/complete_in_ifconfig.swift new file mode 100644 index 0000000000000..56b8bcfe46b6b --- /dev/null +++ b/test/IDE/complete_in_ifconfig.swift @@ -0,0 +1,75 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t + +struct MyStruct { + init() {} + var value: Int +} + +// MEMBER_MyStruct: Begin completions, 2 items +// MEMBER_MyStruct-DAG: Keyword[self]/CurrNominal: self[#MyStruct#]; +// MEMBER_MyStruct-DAG: Decl[InstanceVar]/CurrNominal: value[#Int#]; +// MEMBER_MyStruct: End completions + +#if true +let toplevelActive = MyStruct() +_ = toplevelActive.#^MEMBER_TOPLEVEL_ACTIVE?check=MEMBER_MyStruct^# +#else +let toplevelInactive = MyStruct() +_ = toplevelInactive.#^MEMBER_TOPLEVEL_INACTIVE?check=MEMBER_MyStruct^# +#endif + +func foo() { +#if true + let infuncActive = MyStruct() + _ = infuncActive.#^MEMBER_INFUNC_ACTIVE?check=MEMBER_MyStruct^# +#else + let infuncInactive = MyStruct() + _ = infuncInactive.#^MEMBER_INFUNC_INACTIVE?check=MEMBER_MyStruct^# +#endif +} + +protocol TestP { + func foo() + func bar() +} +struct TestStruct: TestP { +#if true + func foo() {} + func #^OVERRIDE_ACTIVE^# +// OVERRIDE_ACTIVE: Begin completions, 1 items +// OVERRIDE_ACTIVE-DAG: Decl[InstanceMethod]/Super: bar() {|}; +// OVERRIDE_ACTIVE: End completions +#else + func bar() {} + func #^OVERRIDE_INACTIVE^# +// OVERRIDE_INACTIVE: Begin completions, 1 items +// OVERRIDE_INACTIVE-DAG: Decl[InstanceMethod]/Super: foo() {|}; +// OVERRIDE_INACTIVE: End completions +#endif +} + +struct TestStruct2 { +#if true + func activeFunc() {} + func test() { + self.#^SELF_ACTIVE^# + } +// SELF_ACTIVE: Begin completions, 3 items +// SELF_ACTIVE-DAG: Keyword[self]/CurrNominal: self[#TestStruct2#]; +// SELF_ACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: activeFunc()[#Void#]; +// SELF_ACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: test()[#Void#]; +// SELF_ACTIVE: End completions +#else + func inactiveFunc() {} + func test() { + self.#^SELF_INACTIVE^# + } +// SELF_INACTIVE: Begin completions, 3 items +// SELF_INACTIVE-DAG: Keyword[self]/CurrNominal: self[#TestStruct2#]; +// SELF_INACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: inactiveFunc()[#Void#]; +// SELF_INACTIVE-DAG: Decl[InstanceMethod]/CurrNominal: test()[#Void#]; +// SELF_INACTIVE: End completions +#endif +} + From 66531729eb66efad1c0ad8f26d91e97514c02308 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 13 Aug 2020 19:03:09 -0700 Subject: [PATCH 146/663] [ASTScope] Remove includeInactiveIfConfigClauses flag This flag has never been enabled. Now that, Parser treats IfConfig block containing CC token as "active", so code completion doesn't lookup from inactive blocks. --- include/swift/AST/NameLookup.h | 2 -- lib/AST/ASTScopeCreation.cpp | 40 +--------------------------------- 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index ea847ce01c1ba..a6b7c75905b04 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -741,8 +741,6 @@ class ASTScope { return Mem; } - static bool areInactiveIfConfigClausesSupported(); - private: static ast_scope::ASTSourceFileScope *createScopeTree(SourceFile *); diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 6c1336d48d9e2..4623e38970ea3 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -479,23 +479,6 @@ class ScopeCreator final { } public: - /// When ASTScopes are enabled for code completion, - /// IfConfigs will pose a challenge because we may need to field lookups into - /// the inactive clauses, but the AST contains redundancy: the active clause's - /// elements are present in the members or elements of an IterableTypeDecl or - /// BraceStmt alongside of the IfConfigDecl. In addition there are two more - /// complications: - /// - /// 1. The active clause's elements may be nested inside an init self - /// rebinding decl (as in StringObject.self). - /// - /// 2. The active clause may be before or after the inactive ones - /// - /// So, when encountering an IfConfigDecl, we will expand the inactive - /// elements. Also, always sort members or elements so that the child scopes - /// are in source order (Just one of several reasons we need to sort.) - /// - static const bool includeInactiveIfConfigClauses = false; private: static std::vector expandIfConfigClauses(ArrayRef input) { @@ -526,9 +509,6 @@ class ScopeCreator final { if (isa(d)) expandIfConfigClausesInto(expansion, {d}, true); } - } else if (includeInactiveIfConfigClauses) { - expandIfConfigClausesInto(expansion, clause.Elements, - /*isInAnActiveNode=*/false); } } } @@ -762,10 +742,6 @@ void ASTScope:: impl->buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); } -bool ASTScope::areInactiveIfConfigClausesSupported() { - return ScopeCreator::includeInactiveIfConfigClauses; -} - void ASTScope::expandFunctionBody(AbstractFunctionDecl *AFD) { auto *const SF = AFD->getParentSourceFile(); SF->getScope().expandFunctionBodyImpl(AFD); @@ -2083,10 +2059,8 @@ class LocalizableDeclContextCollector : public ASTWalker { // catchForDebugging(D, "DictionaryBridging.swift", 694); if (const auto *dc = dyn_cast(D)) record(dc); - if (auto *icd = dyn_cast(D)) { - walkToClauses(icd); + if (isa(D)) return false; - } if (auto *pd = dyn_cast(D)) record(pd->getDefaultArgumentInitContext()); else if (auto *pbd = dyn_cast(D)) @@ -2104,18 +2078,6 @@ class LocalizableDeclContextCollector : public ASTWalker { } private: - void walkToClauses(IfConfigDecl *icd) { - for (auto &clause : icd->getClauses()) { - // Generate scopes for any closures in the condition - if (ScopeCreator::includeInactiveIfConfigClauses && clause.isActive) { - if (clause.Cond) - clause.Cond->walk(*this); - for (auto n : clause.Elements) - n.walk(*this); - } - } - } - void recordInitializers(PatternBindingDecl *pbd) { for (auto idx : range(pbd->getNumPatternEntries())) record(pbd->getInitContext(idx)); From dd6046ba1662a66ab144bd33684a50162db43000 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 14 Aug 2020 10:28:22 -0700 Subject: [PATCH 147/663] [CodeCompletion] Stop recording interface hash when searching CC token --- lib/Parse/ParseIfConfig.cpp | 2 + .../complete_sequence_in_ifconfig.swift | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 test/SourceKit/CodeComplete/complete_sequence_in_ifconfig.swift diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index 01732baf417f9..938c6de0ddaa6 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -614,6 +614,7 @@ ParserResult Parser::parseIfConfig( bool hasCCToken = false; if (SourceMgr.hasCodeCompletionBuffer() && SourceMgr.getCodeCompletionBufferID() == L->getBufferID()) { + llvm::SaveAndRestore> H(CurrentTokenHash, None); BacktrackingScope backtrack(*this); auto startLoc = Tok.getLoc(); skipSingle(); @@ -676,6 +677,7 @@ ParserResult Parser::parseIfConfig( // Treat the region containing code completion token as "active". if (hasCCToken && !foundActive) { + llvm::SaveAndRestore> H(CurrentTokenHash, None); BacktrackingScope backtrack(*this); auto startLoc = Tok.getLoc(); skipUntilConditionalBlockClose(); diff --git a/test/SourceKit/CodeComplete/complete_sequence_in_ifconfig.swift b/test/SourceKit/CodeComplete/complete_sequence_in_ifconfig.swift new file mode 100644 index 0000000000000..50c4acd8163ec --- /dev/null +++ b/test/SourceKit/CodeComplete/complete_sequence_in_ifconfig.swift @@ -0,0 +1,54 @@ +struct MyStruct { + init() {} + var value: Int = 1 +} + +func foo(arg: MyStruct) { + #if true + _ = arg./*8:11*/ + #else + _ = arg./*10:11*/ + #endif +} + +struct TestStruct { + #if true + func testActive(arg: MyStruct) { + _ = arg./*17:13*/ + } + #else + func testInactive(arg: MyStruct) { + _ = arg./*21:13*/ + } + #endif +} + +// Test that (1) fast completion happens even in inactive #if blocks, and +// (2) #if in toplevel decls invalidate cached ASTContext + +// RUN: %sourcekitd-test \ +// RUN: -req=complete -pos=8:11 %s -- %s -parse-as-library == \ +// RUN: -req=complete -pos=10:11 %s -- %s -parse-as-library == \ +// RUN: -req=complete -pos=17:13 %s -- %s -parse-as-library == \ +// RUN: -req=complete -pos=21:13 %s -- %s -parse-as-library \ +// RUN: | %FileCheck %s --check-prefix=RESULT + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT-NOT: key.reusingastcontext: 1 + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT: key.reusingastcontext: 1 + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT: key.reusingastcontext: 1 + +// RESULT-LABEL: key.results: [ +// RESULT-DAG: key.description: "value" +// RESULT: ] +// RESULT-NOT: key.reusingastcontext: 1 From 7198b3bd83d7f0a409c663ec6788bb4e32847f02 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 14 Aug 2020 09:04:08 -0700 Subject: [PATCH 148/663] [CodeCompletion] Fast completion is now supported in inactive #if blocks --- lib/IDE/CompletionInstance.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 54bcf8a8cc0ee..2f8a6cd7040b5 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -85,8 +85,6 @@ template Decl *getElementAt(const Range &Decls, unsigned N) { /// Find the equivalent \c DeclContext with \p DC from \p SF AST. /// This assumes the AST which contains \p DC has exact the same structure with /// \p SF. -/// FIXME: This doesn't support IfConfigDecl blocks. If \p DC is in an inactive -/// config block, this function returns \c false. static DeclContext *getEquivalentDeclContextFromSourceFile(DeclContext *DC, SourceFile *SF) { PrettyStackTraceDeclContext trace("getting equivalent decl context for", DC); @@ -129,7 +127,6 @@ static DeclContext *getEquivalentDeclContextFromSourceFile(DeclContext *DC, } // Not found in the decl context tree. - // FIXME: Probably DC is in an inactive #if block. if (N == ~0U) { return nullptr; } From e374bc7aa513f20c78e7ba39c897b6cba6f087df Mon Sep 17 00:00:00 2001 From: Yersultan Sapar Date: Fri, 7 Aug 2020 19:02:04 -0700 Subject: [PATCH 149/663] Added compatible ObjC string for keypath argument of the dynamic member lookup subscript. --- lib/Sema/CSApply.cpp | 42 +++++++++++++++++++------------ test/SILGen/keypaths_objc.swift | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 056dcd9dbacc7..e79f88b316a71 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -361,6 +361,26 @@ namespace { return base.getOldType(); } + /// Check whether it is possible to have an ObjC key path string for the keypath expression + /// and set the key path string, if yes + void checkAndSetObjCKeyPathString(KeyPathExpr *keyPath) { + if (cs.getASTContext().LangOpts.EnableObjCInterop) { + SmallString<64> compatStringBuf; + if (buildObjCKeyPathString(keyPath, compatStringBuf)) { + auto stringCopy = cs.getASTContext().AllocateCopy(compatStringBuf.begin(), + compatStringBuf.end()); + auto stringExpr = new (cs.getASTContext()) StringLiteralExpr( + StringRef(stringCopy, compatStringBuf.size()), + SourceRange(), + /*implicit*/ true); + cs.setType( + stringExpr, + cs.getASTContext().getStringDecl()->getDeclaredInterfaceType()); + keyPath->setObjCStringLiteralExpr(stringExpr); + } + } + } + // Returns None if the AST does not contain enough information to recover // substitutions; this is different from an Optional(SubstitutionMap()), // indicating a valid call to a non-generic operator. @@ -2007,6 +2027,11 @@ namespace { keyPath->setParsedPath(componentExpr); keyPath->resolveComponents(ctx, components); cs.cacheExprTypes(keyPath); + + // See whether there's an equivalent ObjC key path string we can produce + // for interop purposes. + checkAndSetObjCKeyPathString(keyPath); + return keyPath; } @@ -4711,22 +4736,7 @@ namespace { // See whether there's an equivalent ObjC key path string we can produce // for interop purposes. - if (cs.getASTContext().LangOpts.EnableObjCInterop) { - SmallString<64> compatStringBuf; - if (buildObjCKeyPathString(E, compatStringBuf)) { - auto stringCopy = - cs.getASTContext().AllocateCopy(compatStringBuf.begin(), - compatStringBuf.end()); - auto stringExpr = new (cs.getASTContext()) StringLiteralExpr( - StringRef(stringCopy, compatStringBuf.size()), - SourceRange(), - /*implicit*/ true); - cs.setType( - stringExpr, - cs.getASTContext().getStringDecl()->getDeclaredInterfaceType()); - E->setObjCStringLiteralExpr(stringExpr); - } - } + checkAndSetObjCKeyPathString(E); // The final component type ought to line up with the leaf type of the // key path. diff --git a/test/SILGen/keypaths_objc.swift b/test/SILGen/keypaths_objc.swift index 215847db3e443..b5603386f5876 100644 --- a/test/SILGen/keypaths_objc.swift +++ b/test/SILGen/keypaths_objc.swift @@ -113,3 +113,47 @@ class OverrideFrameworkObjCProperty: A { func overrideFrameworkObjCProperty() { let _ = \OverrideFrameworkObjCProperty.counter } + +@dynamicMemberLookup +class DynamicClass { + init() {} + subscript(dynamicMember member: KeyPath) -> DynamicClass { + fatalError() + } +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}dynamicMemberLookupSimple +func dynamicMemberLookupSimple(foo: DynamicClass, nonobjc: DynamicClass) { + // CHECK: keypath $KeyPath, (objc "bar" + _ = foo.bar + // CHECK: keypath $KeyPath, (objc "int" + _ = foo.int + // CHECK: keypath $KeyPath, (objc "bar" + // CHECK: keypath $KeyPath, (objc "foo" + _ = foo.bar.foo + // CHECK: keypath $KeyPath, (root + _ = foo.nonobjc + // CHECK: keypath $KeyPath, (objc "thisIsADifferentName" + _ = foo.differentName + // CHECK: keypath $KeyPath, (root + _ = nonobjc.x + // CHECK: keypath $KeyPath, (root + _ = nonobjc.y +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}dynamicMemberLookupNestedKeypaths +func dynamicMemberLookupNestedKeypaths(foo: DynamicClass) { + // CHECK: keypath $KeyPath, (objc "bar" + // CHECK: keypath $KeyPath, (objc "foo" + // CHECK: keypath $KeyPath, (objc "bar" + _ = foo.bar.foo.bar +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}dynamicMemberLookupMixedKeypaths +func dynamicMemberLookupMixedKeypaths(foo: DynamicClass) { + // CHECK: keypath $KeyPath, (objc "bar" + // CHECK: keypath $KeyPath, (objc "foo" + // CHECK: keypath $KeyPath, (root + // CHECK: keypath $KeyPath, (root + _ = foo.bar.foo.nonobjc.y +} \ No newline at end of file From 6cfdaf662de109275956665e8180fd93f671fa69 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 14 Aug 2020 11:03:16 -0700 Subject: [PATCH 150/663] [CodeCompletion] Reduce backtracking for searching CC token in IfConfig --- lib/Parse/ParseIfConfig.cpp | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index 938c6de0ddaa6..4dd005cb9cef9 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -610,17 +610,25 @@ ParserResult Parser::parseIfConfig( Parser::StructureMarkerRAII ParsingDecl( *this, Tok.getLoc(), Parser::StructureMarkerKind::IfConfig); - // See if this '#if ... #endif' directive contains code completion token. - bool hasCCToken = false; + // Find the region containing code completion token. + SourceLoc codeCompletionClauseLoc; if (SourceMgr.hasCodeCompletionBuffer() && - SourceMgr.getCodeCompletionBufferID() == L->getBufferID()) { + SourceMgr.getCodeCompletionBufferID() == L->getBufferID() && + SourceMgr.isBeforeInBuffer(Tok.getLoc(), + SourceMgr.getCodeCompletionLoc())) { llvm::SaveAndRestore> H(CurrentTokenHash, None); BacktrackingScope backtrack(*this); - auto startLoc = Tok.getLoc(); - skipSingle(); - auto endLoc = PreviousLoc; - hasCCToken = SourceMgr.rangeContainsTokenLoc( - SourceRange(startLoc, endLoc), SourceMgr.getCodeCompletionLoc()); + do { + auto startLoc = Tok.getLoc(); + consumeToken(); + skipUntilConditionalBlockClose(); + auto endLoc = PreviousLoc; + if (SourceMgr.rangeContainsTokenLoc(SourceRange(startLoc, endLoc), + SourceMgr.getCodeCompletionLoc())){ + codeCompletionClauseLoc = startLoc; + break; + } + } while (Tok.isNot(tok::pound_endif, tok::eof)); } bool shouldEvaluate = @@ -628,9 +636,9 @@ ParserResult Parser::parseIfConfig( shouldEvaluatePoundIfDecls() && // If it's in inactive #if ... #endif block, there's no point to do it. !getScopeInfo().isInactiveConfigBlock() && - // If this directive contains code completion, 'isActive' is determined - // solely by which block has the completion token. - !hasCCToken; + // If this directive contains code completion location, 'isActive' is + // determined solely by which block has the completion token. + !codeCompletionClauseLoc.isValid(); bool foundActive = false; bool isVersionCondition = false; @@ -676,15 +684,8 @@ ParserResult Parser::parseIfConfig( } // Treat the region containing code completion token as "active". - if (hasCCToken && !foundActive) { - llvm::SaveAndRestore> H(CurrentTokenHash, None); - BacktrackingScope backtrack(*this); - auto startLoc = Tok.getLoc(); - skipUntilConditionalBlockClose(); - auto endLoc = PreviousLoc; - isActive = SourceMgr.rangeContainsTokenLoc( - SourceRange(startLoc, endLoc), SourceMgr.getCodeCompletionLoc()); - } + if (codeCompletionClauseLoc.isValid() && !foundActive) + isActive = (ClauseLoc == codeCompletionClauseLoc); foundActive |= isActive; From a5a7c98be07d73a271e3220c9091ce8ad78c2502 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 13 Aug 2020 13:06:21 -0700 Subject: [PATCH 151/663] [metadata prespecialization] getGenericMetadata finds records. Previously, the metadata accessor for which canonical prespecializations had been formed included checks against the passed-in arguments to determine whether the access matched a prespecialized record or not. Now that the prespecialized records are attached to the nominal type descriptor for the type, eliminate this hard-coded generated code and instead let swift_getGenericMetadata do the work of looking through the prespecializations. --- lib/IRGen/GenDecl.cpp | 19 +- lib/IRGen/IRGenModule.h | 5 - lib/IRGen/MetadataRequest.cpp | 190 ------------------ stdlib/public/runtime/Metadata.cpp | 41 ++++ ...-2nd_argument_distinct_generic_class.swift | 84 -------- ...t_same_generic_class_different_value.swift | 84 -------- ...gument_same_generic_class_same_value.swift | 84 -------- ...n_int-2nd_anc_gen-1st-arg_con_double.swift | 42 ---- ...int-2nd_anc_gen-1st-arg_subclass_arg.swift | 42 ---- ...lass_arg-2nd_anc_gen-1st-arg_con_int.swift | 42 ---- ...s_arg-2nd_anc_gen-1st-arg_subcls_arg.swift | 42 ---- ...1st_argument_generic_class-1argument.swift | 14 -- ...ate-inmodule-1argument-1distinct_use.swift | 12 -- ...argument-1distinct_use_generic_class.swift | 49 ----- ...c_class_specialized_at_generic_class.swift | 49 ----- ...1argument-1distinct_use_generic_enum.swift | 29 --- ...rgument-1distinct_use_generic_struct.swift | 32 --- ...ate-inmodule-1argument-1distinct_use.swift | 25 --- ...within-class-1argument-1distinct_use.swift | 25 --- ...1argument-1conformance-1distinct_use.swift | 49 ----- ...nt-1conformance-public-1distinct_use.swift | 49 ----- ...num-inmodule-1argument-1distinct_use.swift | 8 - ...within-class-1argument-1distinct_use.swift | 28 --- ...-within-enum-1argument-1distinct_use.swift | 28 --- ...ithin-struct-1argument-1distinct_use.swift | 27 --- ...num-inmodule-2argument-1distinct_use.swift | 28 --- ...num-inmodule-3argument-1distinct_use.swift | 32 --- ...num-inmodule-4argument-1distinct_use.swift | 43 ---- ...num-inmodule-5argument-1distinct_use.swift | 48 ----- ...stinct_use-external_resilient-frozen.swift | 25 --- ...1argument-1distinct_use-payload_size.swift | 25 --- ...ate-inmodule-1argument-1distinct_use.swift | 8 - ...within-class-1argument-1distinct_use.swift | 8 - ...1argument-1conformance-1distinct_use.swift | 31 --- ...dule-1argument-1distinct_generic_use.swift | 74 ------- ...uct-inmodule-1argument-1distinct_use.swift | 8 - ...1argument-2conformance-1distinct_use.swift | 54 ----- ...uct-inmodule-1argument-2distinct_use.swift | 14 -- ...1argument-3conformance-1distinct_use.swift | 85 -------- ...uct-inmodule-1argument-3distinct_use.swift | 20 -- ...1argument-4conformance-1distinct_use.swift | 110 ---------- ...uct-inmodule-1argument-4distinct_use.swift | 26 --- ...1argument-5conformance-1distinct_use.swift | 135 ------------- ...uct-inmodule-1argument-5distinct_use.swift | 32 --- ...within-class-1argument-1distinct_use.swift | 29 --- ...-within-enum-1argument-1distinct_use.swift | 29 --- ...ithin-struct-1argument-1distinct_use.swift | 28 --- ...ension-equal_arguments-1distinct_use.swift | 30 --- ...uct-inmodule-2argument-1distinct_use.swift | 10 - ...uct-inmodule-2argument-2distinct_use.swift | 18 -- ...uct-inmodule-2argument-3distinct_use.swift | 26 --- ...uct-inmodule-2argument-4distinct_use.swift | 34 ---- ...uct-inmodule-2argument-5distinct_use.swift | 42 ---- ...within-class-1argument-1distinct_use.swift | 12 -- ...lic-inmodule-1argument-1distinct_use.swift | 8 - 55 files changed, 45 insertions(+), 2126 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 60e858219a608..166c7dc5d1c13 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1164,21 +1164,10 @@ void IRGenerator::emitTypeMetadataRecords() { } } -void IRGenerator:: - deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( - IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, - NominalTypeDecl &decl) { - // The accessor depends on canonical metadata records because they are - // returned from the function when the arguments match. - // - // TODO: Once work of looking through canonical prespecialized metadata has - // been moved into getGenericMetadata, this reemission will no longer - // be necessary. - auto *accessor = IGM.getAddrOfTypeMetadataAccessFunction( - decl.getDeclaredType()->getCanonicalType(), NotForDefinition); - accessor->deleteBody(); - IGM.IRGen.noteUseOfMetadataAccessor(&decl); - +static void +deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( + IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, + NominalTypeDecl &decl) { // The type context descriptor depends on canonical metadata records because // pointers to them are attached as trailing objects to it. // diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index d9de7a41bb624..909b3702eed6a 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -436,11 +436,6 @@ class IRGenerator { return MetadataPrespecializationsForGenericTypes.lookup(type); } - void - deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( - IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, - NominalTypeDecl &decl); - void noteUseOfMetadataAccessor(NominalTypeDecl *decl) { if (LazyMetadataAccessors.count(decl) == 0) { LazyMetadataAccessors.insert(decl); diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 17235dfa35afb..d3f9fe58b6a16 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1986,176 +1986,6 @@ IRGenFunction::emitGenericTypeMetadataAccessFunctionCall( return MetadataResponse::handle(*this, request, call); } -static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( - IRGenFunction &IGF, llvm::Value *request, NominalTypeDecl *nominal, - GenericArguments &genericArgs, - std::function valueAtIndex) { - auto &IGM = IGF.IGM; - auto specializations = IGM.IRGen.metadataPrespecializationsForType(nominal); - auto canonicalCount = llvm::count_if(specializations, [](auto pair) { - return pair.second == TypeMetadataCanonicality::Canonical; - }); - - if (canonicalCount > 0) { - SmallVector conditionBlocks; - for (size_t index = 0; index < specializations.size(); ++index) { - conditionBlocks.push_back(llvm::BasicBlock::Create(IGM.getLLVMContext())); - } - - IGF.Builder.CreateBr(conditionBlocks[0]); - - SmallVector>, - 4> - specializationBlocks; - auto switchDestination = llvm::BasicBlock::Create(IGM.getLLVMContext()); - unsigned long blockIndex = 0; - for (auto pair : specializations) { - if (pair.second != TypeMetadataCanonicality::Canonical) { - continue; - } - auto specialization = pair.first; - auto conditionBlock = conditionBlocks[blockIndex]; - IGF.Builder.emitBlock(conditionBlock); - auto successorBlock = blockIndex < conditionBlocks.size() - 1 - ? conditionBlocks[blockIndex + 1] - : switchDestination; - auto specializationBlock = llvm::BasicBlock::Create(IGM.getLLVMContext()); - auto substitutions = specialization->getContextSubstitutionMap( - IGM.getSwiftModule(), nominal); - - llvm::Value *condition = llvm::ConstantInt::get(IGM.Int1Ty, 1); - auto nominal = specialization->getAnyNominal(); - auto requirements = GenericTypeRequirements(IGM, nominal); - int requirementIndex = 0; - for (auto requirement : requirements.getRequirements()) { - auto parameter = requirement.TypeParameter; - auto argument = parameter.subst(substitutions); - if (requirement.Protocol) { - auto conformance = substitutions.lookupConformance( - requirement.TypeParameter->getCanonicalType(), - requirement.Protocol); - ProtocolConformance *concreteConformance = conformance.getConcrete(); - auto argumentNominal = argument->getAnyNominal(); - if (argumentNominal && argumentNominal->isGenericContext()) { - // TODO: Statically specialize the witness table pattern for t's - // conformance. - llvm_unreachable( - "Statically specializing metadata at generic types is " - "not supported."); - } else { - RootProtocolConformance *rootConformance = - concreteConformance->getRootConformance(); - llvm::Value *expectedDescriptor = - IGM.getAddrOfProtocolConformanceDescriptor(rootConformance); - auto *witnessTable = valueAtIndex(requirementIndex); - auto *witnessBuffer = - IGF.Builder.CreateBitCast(witnessTable, IGM.Int8PtrPtrTy); - auto *uncastProvidedDescriptor = - IGF.Builder.CreateLoad(witnessBuffer, Alignment()); - auto *providedDescriptor = IGF.Builder.CreateBitCast( - uncastProvidedDescriptor, - IGM.ProtocolConformanceDescriptorPtrTy); - - // Auth the stored descriptor. - auto storedScheme = - IGM.getOptions().PointerAuth.ProtocolConformanceDescriptors; - if (storedScheme) { - auto authInfo = PointerAuthInfo::emit( - IGF, storedScheme, witnessTable, - PointerAuthEntity::Special::ProtocolConformanceDescriptor); - providedDescriptor = - emitPointerAuthAuth(IGF, providedDescriptor, authInfo); - } - - // Sign the descriptors. - auto argScheme = - IGM.getOptions() - .PointerAuth.ProtocolConformanceDescriptorsAsArguments; - if (argScheme) { - auto authInfo = PointerAuthInfo::emit( - IGF, argScheme, nullptr, - PointerAuthEntity::Special:: - ProtocolConformanceDescriptorAsArgument); - expectedDescriptor = - emitPointerAuthSign(IGF, expectedDescriptor, authInfo); - providedDescriptor = - emitPointerAuthSign(IGF, providedDescriptor, authInfo); - } - - auto *call = IGF.Builder.CreateCall( - IGM.getCompareProtocolConformanceDescriptorsFn(), - {providedDescriptor, expectedDescriptor}); - call->setDoesNotThrow(); - call->setCallingConv(IGM.SwiftCC); - call->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::ReadNone); - condition = IGF.Builder.CreateAnd(condition, call); - } - } else { - llvm::Constant *addr = - IGM.getAddrOfTypeMetadata(argument->getCanonicalType()); - auto addrInt = IGF.Builder.CreateBitCast(addr, IGM.Int8PtrTy); - condition = IGF.Builder.CreateAnd( - condition, IGF.Builder.CreateICmpEQ( - addrInt, valueAtIndex(requirementIndex))); - } - ++requirementIndex; - } - IGF.Builder.CreateCondBr(condition, specializationBlock, successorBlock); - - auto responseBuilder = [](llvm::Value *request, CanType specialization, - IRGenFunction &IGF, IRGenModule &IGM) { - auto nominal = specialization->getAnyNominal(); - llvm::Value *specializedMetadata; - if (isa(nominal)) { - llvm::Function *accessor = - IGM - .getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction( - specialization, NotForDefinition); - - specializedMetadata = - IGF.emitGenericTypeMetadataAccessFunctionCall( - accessor, {}, DynamicMetadataRequest(request)) - .getMetadata(); - } else { - specializedMetadata = IGM.getAddrOfTypeMetadata(specialization); - } - // Construct a MetadataResponse. It has three fields in the following - // order: - // - const Metadata *Metadata; - // - MetadataState (i32) StaticState; - llvm::Value *response = - llvm::UndefValue::get(IGM.TypeMetadataResponseTy); - response = IGF.Builder.CreateInsertValue( - response, specializedMetadata, 0, - "insert metadata address into response"); - auto state = MetadataResponse::getCompletedState(IGM); - response = IGF.Builder.CreateInsertValue( - response, state, 1, "insert metadata state into response"); - return response; - }; - specializationBlocks.push_back(std::make_tuple( - specializationBlock, specialization, responseBuilder)); - ++blockIndex; - } - - for (auto tuple : specializationBlocks) { - llvm::BasicBlock *block; - CanType type; - std::function - builder; - std::tie(block, type, builder) = tuple; - IGF.Builder.emitBlock(block); - IGF.Builder.CreateRet(builder(request, type, IGF, IGM)); - } - IGF.Builder.emitBlock(switchDestination); - } -} - MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( IRGenFunction &IGF, Explosion ¶ms, NominalTypeDecl *nominal, GenericArguments &genericArgs) { @@ -2186,20 +2016,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( llvm::Value *arguments = IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrTy); - llvm::Value *argumentsBuffer = - IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrPtrTy); - - emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( - IGF, request, nominal, genericArgs, [&](int index) { - llvm::Value *indexValue = llvm::ConstantInt::get(IGM.Int64Ty, index); - llvm::Value *elementPointer = - IGF.Builder.CreateGEP(argumentsBuffer, indexValue); - llvm::LoadInst *retval = IGF.Builder.CreateLoad( - elementPointer, Alignment(), - llvm::formatv("load argument at index {0} from buffer", index)); - return retval; - }); - // Make the call. auto call = IGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(), {request, arguments, descriptor}); @@ -2278,12 +2094,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( ? IGF.Builder.CreateBitCast(params.claimNext(), IGM.Int8PtrTy) : llvm::UndefValue::get(IGM.Int8PtrTy); - std::array argValues = {arg0, arg1, arg2}; - - emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( - IGF, request, nominal, genericArgs, - [&](int index) { return argValues[index]; }); - auto call = IGF.Builder.CreateCall(thunkFn, {request, arg0, arg1, arg2, descriptor}); call->setDoesNotAccessMemory(); diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 34f4bc71a8252..6d27888429c13 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -756,12 +756,53 @@ MetadataResponse swift::swift_getCanonicalSpecializedMetadata( return result.second; } +// Look into the canonical prespecialized metadata attached to the type +// descriptor and return matching records, if any. +static Metadata * +findCanonicalSpecializedMetadata(MetadataRequest request, + const void *const *arguments, + const TypeContextDescriptor *description) { + auto &cache = getCache(*description); + auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + arguments); + auto prespecializedMetadatas = + description->getCanonicicalMetadataPrespecializations(); + int index = 0; + for (auto &prespecializedMetadataPtr : prespecializedMetadatas) { + Metadata *prespecializationMetadata = prespecializedMetadataPtr.get(); + const void *const *prespecializationArguments = + reinterpret_cast( + prespecializationMetadata->getGenericArgs()); + auto prespecializationKey = + MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + prespecializationArguments); + if (key == prespecializationKey) { + if (auto *classDescription = dyn_cast(description)) { + auto canonicalMetadataAccessors = + classDescription->getCanonicalMetadataPrespecializationAccessors(); + auto &canonicalMetadataAccessorPtr = canonicalMetadataAccessors[index]; + auto *canonicalMetadataAccessor = canonicalMetadataAccessorPtr.get(); + auto response = canonicalMetadataAccessor(request); + return const_cast(response.Value); + } else { + return prespecializationMetadata; + } + } + ++index; + } + return nullptr; +} + /// The primary entrypoint. MetadataResponse swift::swift_getGenericMetadata(MetadataRequest request, const void * const *arguments, const TypeContextDescriptor *description) { description = swift_auth_data_non_address(description, SpecialPointerAuthDiscriminators::TypeDescriptor); + if (auto *prespecialization = + findCanonicalSpecializedMetadata(request, arguments, description)) { + return {prespecialization, MetadataState::Complete}; + } auto &cache = getCache(*description); assert(description->getFullGenericContextHeader().Base.NumKeyArguments == cache.NumKeyParameters + cache.NumWitnessTables); diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift index 4343391e57e12..8e087b91ceed0 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_distinct_generic_class.swift @@ -238,90 +238,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_ARGUMENT1:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT1_METADATA]] to i8* // CHECK: [[ERASED_ARGUMENT2:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT2_METADATA]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// CHECK-SAME: ), [[ERASED_ARGUMENT1]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument2[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument2[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// CHECK-SAME: }>* @"$s4main9Argument2[[UNIQUE_ID_1]]LLCySSGMf" to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// : ), [[ERASED_ARGUMENT2]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1]], [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA9Argument1ACLLCySiGAA9Argument2ACLLCySSGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_ARGUMENT1]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift index 782a1c22d4cc7..bc1dd0c10b5fc 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_different_value.swift @@ -228,90 +228,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_ARGUMENT1:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT1_METADATA]] to i8* // CHECK: [[ERASED_ARGUMENT2:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT2_METADATA]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// CHECK-SAME: ), [[ERASED_ARGUMENT1]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// CHECK-SAME: }>* @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySSGMf" to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// : ), [[ERASED_ARGUMENT2]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1]], [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA9Argument1ACLLCySiGAFySSGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_ARGUMENT1]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift index 063e19e254d90..d0122ee20739d 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-2argument-1_distinct_use-1st_argument_generic_class-2nd_argument_same_generic_class_same_value.swift @@ -228,90 +228,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_ARGUMENT1:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT1_METADATA]] to i8* // CHECK: [[ERASED_ARGUMENT2:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT2_METADATA]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// CHECK-SAME: ), [[ERASED_ARGUMENT1]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// CHECK-SAME: }>* @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf" to %swift.full_heapmetadata* -// : ), -// : i32 0, -// : i32 2 -// : ) to i8* -// : ), [[ERASED_ARGUMENT2]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1]], [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA9Argument1ACLLCySiGAGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_ARGUMENT1]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift index 04e01f00adbc6..a6e82b06a8531 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_con_double.swift @@ -239,20 +239,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSdN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]CySdGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -270,20 +256,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -301,20 +273,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift index 1441ee49f2a05..d31da831d35b7 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_con_int-2nd_anc_gen-1st-arg_subclass_arg.swift @@ -224,20 +224,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -255,20 +241,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -286,20 +258,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift index 9cca1c2489be4..571080fd0c496 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subclass_arg-2nd_anc_gen-1st-arg_con_int.swift @@ -228,20 +228,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -259,20 +245,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -290,20 +262,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSSN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySSGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift index 1558d95bea74a..0cf8847101f25 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1arg-2ancs-1distinct_use-1st_anc_gen-1arg-1st_arg_subcls_arg-2nd_anc_gen-1st-arg_subcls_arg.swift @@ -216,20 +216,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* [[ARGUMENT:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor2[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -247,20 +233,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* [[ARGUMENT:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9Ancestor1[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -278,20 +250,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* [[ARGUMENT:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$sSiN" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] [[METADATA_REQUEST]], // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift index 1648484f0de4c..8bf4826b10b70 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use-1st_argument_generic_class-1argument.swift @@ -256,20 +256,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]CySiGMf" -// CHECK-SAME: ), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CyAA9Argument1ACLLCySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift index d1b52bed77166..8ba996f2c6243 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use.swift @@ -101,18 +101,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CySiGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift index 2cf41486a5b49..b792ac6dfb932 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class.swift @@ -193,55 +193,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main3Box[[UNIQUE_ID_2]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main3Box[[UNIQUE_ID_2]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main3Box[[UNIQUE_ID_1]]LLCySiGMf" -// : to %swift.full_heapmetadata* -// : ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 2 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA3BoxACLLCySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift index 8579ac2e32306..0bdef4eb2cf22 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_class_specialized_at_generic_class.swift @@ -200,55 +200,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]LLCMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// : %swift.type* getelementptr inbounds ( -// : %swift.full_heapmetadata, -// : %swift.full_heapmetadata* bitcast ( -// : <{ -// : void ( -// : %T4main3Box[[UNIQUE_ID_2]]LLC* -// : )*, -// : i8**, -// : [[INT]], -// : %objc_class*, -// : %swift.opaque*, -// : %swift.opaque*, -// : [[INT]], -// : i32, -// : i32, -// : i32, -// : i16, -// : i16, -// : i32, -// : i32, -// : %swift.type_descriptor*, -// : i8*, -// : %swift.type*, -// : [[INT]], -// : %T4main3Box[[UNIQUE_ID_2]]LLC* ( -// : %swift.opaque*, -// : %swift.type* -// : )* -// : }>* -// CHECK-SAME: @"$s4main3Box[[UNIQUE_ID_1]]LLCyAA5InnerACLLCySiGGMf" -// : to %swift.full_heapmetadata* -// : ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 2 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA3BoxACLLCyAA5InnerACLLCySiGGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift index 73d90d620d033..5bbc41092198d 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_enum.swift @@ -171,35 +171,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main6Either[[UNIQUE_ID_1]]OySiGMf" to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CyAA6EitherACLLOySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift index 5d0d352c4716d..fc7680e252c20 100644 --- a/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift +++ b/test/IRGen/prespecialized-metadata/class-fileprivate-inmodule-1argument-1distinct_use_generic_struct.swift @@ -173,38 +173,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]CMa"([[INT]] [[METADATA_REQUEST:%[0-9]+]], %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// : [ -// : 4 x i8 -// : ], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main4Left[[UNIQUE_ID_1]]VySiGMf" to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ) to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]CyAA4LeftACLLVySiGGMb"([[INT]] [[METADATA_REQUEST]]) -// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0 -// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0 -// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1 -// CHECK: ret %swift.metadata_response [[RESULT_METADATA]] -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK: [[INT]] [[METADATA_REQUEST]], // CHECK: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift index 8a7e7f5b64002..3a494d17e3fa8 100644 --- a/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-fileprivate-inmodule-1argument-1distinct_use.swift @@ -58,31 +58,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]OMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5Value[[UNIQUE_ID_1]]OySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift index 944f264a0642c..f79e24b3e4d70 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-0argument-within-class-1argument-1distinct_use.swift @@ -65,31 +65,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main9NamespaceC5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: br i1 [[EQUAL_TYPES_1_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceC5ValueOySi_GMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift index 75f5f86c789c5..630518893d0eb 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift @@ -68,55 +68,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE:%[0-9]+]] = bitcast i8** %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] -// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i8**, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift index 06214ca5a0df9..9687535123ac3 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift @@ -68,55 +68,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE:%[0-9]+]] = bitcast i8** %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] -// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i8**, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift index 2a779835e9856..6e84589deff53 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1distinct_use.swift @@ -62,14 +62,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i64 }>* @"$s4main5ValueOySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* %2, diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift index 9b30b71caf0cf..21a955c1e2231 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-class-1argument-1distinct_use.swift @@ -66,34 +66,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceC5ValueOySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift index 26b68649a8ab9..c1e0c869f9516 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-enum-1argument-1distinct_use.swift @@ -66,34 +66,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceO5ValueOySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift index 31a2ac1032fcc..5919bbbca14f2 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-within-struct-1argument-1distinct_use.swift @@ -66,33 +66,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceV5ValueOySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift index 456565a9e6d8e..a37bd8d51a0f4 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-2argument-1distinct_use.swift @@ -81,34 +81,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS2iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift index 5d7a94d8356ec..b354662dc6f2f 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-3argument-1distinct_use.swift @@ -86,38 +86,6 @@ doit() // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* // CHECK: [[ERASED_TYPE_3:%[0-9]+]] = bitcast %swift.type* %3 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: br i1 [[EQUAL_TYPES_1_3]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS3iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift index 1bdf941808ad3..52928f5303254 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-4argument-1distinct_use.swift @@ -87,49 +87,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: [[ERASED_TYPE_1:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_1]] -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[ERASED_TYPE_ADDRESS_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TYPE_2:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_2]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[ERASED_TYPE_ADDRESS_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TYPE_3:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_3]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: [[ERASED_TYPE_ADDRESS_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TYPE_4:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_4]] -// CHECK: [[EQUAL_TYPE_1_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_4]] -// CHECK: [[EQUAL_TYPES_1_4:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_3]], [[EQUAL_TYPE_1_4]] -// CHECK: br i1 [[EQUAL_TYPES_1_4]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS4iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_BUFFER]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift index 2749bacd8e23f..7ff26cd1f62d2 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-5argument-1distinct_use.swift @@ -86,54 +86,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: [[ERASED_TYPE_1:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_1]] -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[ERASED_TYPE_ADDRESS_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TYPE_2:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_2]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[ERASED_TYPE_ADDRESS_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TYPE_3:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_3]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: [[ERASED_TYPE_ADDRESS_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TYPE_4:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_4]] -// CHECK: [[EQUAL_TYPE_1_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_4]] -// CHECK: [[EQUAL_TYPES_1_4:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_3]], [[EQUAL_TYPE_1_4]] -// CHECK: [[ERASED_TYPE_ADDRESS_5:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 -// CHECK: [[ERASED_TYPE_5:%\".*\"]] = load i8*, i8** [[ERASED_TYPE_ADDRESS_5]] -// CHECK: [[EQUAL_TYPE_1_5:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_5]] -// CHECK: [[EQUAL_TYPES_1_5:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_4]], [[EQUAL_TYPE_1_5]] -// CHECK: br i1 [[EQUAL_TYPES_1_5]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOyS5iGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_BUFFER]], diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift index 9e45d4f245786..5215223884858 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-external_resilient-frozen.swift @@ -66,31 +66,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$s10TestModule7IntegerVN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOy10TestModule7IntegerVGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* %2, diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift index 5b944e2618b4a..6a200c420543a 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-evolution-1argument-1distinct_use-payload_size.swift @@ -78,31 +78,6 @@ doit() // CHECK: define{{( protected)?}} swiftcc %swift.metadata_response @"$s4main5ValueOMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: [[INT]], -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5ValueOySiGMf" to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* %2, diff --git a/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift index cdddc211799bb..071cdb03e2b80 100644 --- a/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-fileprivate-inmodule-1argument-1distinct_use.swift @@ -44,14 +44,6 @@ doit() // CHECK: define internal swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_1]]VMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5Value[[UNIQUE_ID_1]]VySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5Value[[UNIQUE_ID_1]]VMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift index 02abab0244ef8..fa465d41a8544 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-0argument-within-class-1argument-1distinct_use.swift @@ -46,14 +46,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main9NamespaceC5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: br i1 [[EQUAL_TYPES_1_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main9NamespaceC5ValueVySi_GMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift index 9e811bba493b3..80febc5946810 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift @@ -51,37 +51,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE:%[0-9]+]] = bitcast i8** %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] -// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift index 7dc812bb048c3..7798990de8678 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_generic_use.swift @@ -54,53 +54,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5OuterVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast ( -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5InnerVySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ) -// CHECK-SAME: to i8* -// CHECK-SAME: ), -// CHECK-SAME: [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5OuterVyAA5InnerVySiGGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], @@ -117,33 +70,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5InnerVMa"([[INT]] %0, %swift.type* [[TYPE:%[0-9]+]]) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* [[TYPE]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main5InnerVySiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift index fc8e54dcce67a..605c568ca8596 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1distinct_use.swift @@ -44,14 +44,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift index 18faf8c91f44a..93446c7633952 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift @@ -56,60 +56,6 @@ doit() // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TABLE_1:%[0-9]+]] = bitcast i8** %2 to i8* // CHECK: [[ERASED_TABLE_2:%[0-9]+]] = bitcast i8** %3 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE_1]], i8* [[ERASED_TABLE_2]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift index 09d7aea9c2cc5..4ddadcc18122b 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2distinct_use.swift @@ -63,20 +63,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift index 43342719fb133..be61faa0c9c05 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift @@ -58,91 +58,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 -// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_3:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_3]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_3:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_3]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_3]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1RAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_3]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift index 614d85ee5a084..94acd09f2848d 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3distinct_use.swift @@ -84,26 +84,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_3:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3]] -// CHECK: br i1 [[EQUAL_TYPES_3]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift index 2a680000ea99e..ecc6525d7f0c7 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift @@ -62,116 +62,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 -// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_3:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_3]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_3:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_3]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_3]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1RAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] -// CHECK: [[POINTER_TO_ERASED_TABLE_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 -// CHECK: [[ERASED_TABLE_4:%"load argument at index 4 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_4]], align 1 -// CHECK: [[UNERASED_TABLE_4:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_4]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_4]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_4:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_4]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_4:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_4]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_4]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_4:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1SAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_4:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_3]], [[EQUAL_DESCRIPTORS_4]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_4]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift index a60f667a627fe..22eee9e0055db 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4distinct_use.swift @@ -85,32 +85,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_3:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3]] -// CHECK: br i1 [[EQUAL_TYPES_3]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_4:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4]] -// CHECK: br i1 [[EQUAL_TYPES_4]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift index 3bfa8c5834da9..f4dc38b7bdb7f 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift @@ -66,141 +66,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, i8** %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8** %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[ERASED_TYPE_ADDRESS:%[0-9]+]] = getelementptr i8*, i8** %1, i64 0 -// CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 -// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 -// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_1:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_1]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_1:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_1]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_1]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_1]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_1]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_1]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_1]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_1]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1PAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] -// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 -// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 -// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_2:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_2]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_2:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_2]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_2]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_2]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_2]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_2]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_2]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_2]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1QAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] -// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 -// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 -// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_3:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_3]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_3:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_3]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_3]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_3]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_3]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_3]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_3]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_3]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1RAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] -// CHECK: [[POINTER_TO_ERASED_TABLE_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 -// CHECK: [[ERASED_TABLE_4:%"load argument at index 4 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_4]], align 1 -// CHECK: [[UNERASED_TABLE_4:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_4]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_4]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_4:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_4]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_4:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_4]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_4]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_4]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_4]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_4]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_4]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_4:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_4]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1SAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_4:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_3]], [[EQUAL_DESCRIPTORS_4]] -// CHECK: [[POINTER_TO_ERASED_TABLE_5:%[0-9]+]] = getelementptr i8*, i8** %1, i64 5 -// CHECK: [[ERASED_TABLE_5:%"load argument at index 5 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_5]], align 1 -// CHECK: [[UNERASED_TABLE_5:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_5]] to i8** -// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_5:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_5]], align 1 -// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_5:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_5]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[ERASED_TABLE_INT_5:%[0-9]+]] = ptrtoint i8* [[ERASED_TABLE_5]] to i64 -// CHECK-arm64e: [[TABLE_SIGNATURE_5:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ERASED_TABLE_INT_5]], i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_5:%[0-9]+]] = call i64 @llvm.ptrauth.auth.i64(i64 %13, i32 2, i64 [[TABLE_SIGNATURE_5]]) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_5:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_5]] to %swift.protocol_conformance_descriptor* -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_5:%[0-9]+]] = ptrtoint %swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_5]] to i64 -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_5:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_AUTHED_PTR_INT_5]], i32 2, i64 50923) -// CHECK-arm64e: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_5:%[0-9]+]] = inttoptr i64 [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_INT_5]] to %swift.protocol_conformance_descriptor* -// CHECK: [[EQUAL_DESCRIPTORS_5:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors( -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-arm64e-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR_SIGNED_5]], -// CHECK-i386-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-x86_64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7s-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-armv7k-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-arm64-SAME: [[PROVIDED_PROTOCOL_DESCRIPTOR]], -// CHECK-SAME: %swift.protocol_conformance_descriptor* -// CHECK-SAME: $sSi4main1TAAMc -// CHECK-SAME: ) -// CHECK: [[EQUAL_ARGUMENTS_5:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_4]], [[EQUAL_DESCRIPTORS_5]] -// CHECK: br i1 [[EQUAL_ARGUMENTS_5]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[ERASED_ARGUMENT_BUFFER]], %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift index 3a98fe75c3016..01ce8938f9e44 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5distinct_use.swift @@ -123,38 +123,6 @@ doit() // CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]] -// CHECK: br i1 [[EQUAL_TYPES_1]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2]] -// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_3:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3]] -// CHECK: br i1 [[EQUAL_TYPES_3]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_4:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4]] -// CHECK: br i1 [[EQUAL_TYPES_4]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[TYPE_COMPARISON_5:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_5]]: -// CHECK: [[EQUAL_TYPE_5:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss4Int8VN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES_5:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_5]] -// CHECK: br i1 [[EQUAL_TYPES_5]], label %[[EXIT_PRESPECIALIZED_5:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_5]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVys4Int8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift index f4e8311a2ebf1..8353f4754477b 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-class-1argument-1distinct_use.swift @@ -70,35 +70,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32{{(, \[4 x i8\])?}}, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceC5ValueVySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift index 1a789c3b3e237..823d3363802d7 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-enum-1argument-1distinct_use.swift @@ -70,35 +70,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32{{(, \[4 x i8\])?}}, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceO5ValueVySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift index 2a28be73413a7..f0146c3df4869 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-1argument-1distinct_use.swift @@ -70,34 +70,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, %swift.type*, -// CHECK-SAME: i32{{(, \[4 x i8\])?}}, -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceV5ValueVySS_SiGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift index 9d8885fb6b3da..ce004e7edd3b3 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-within-struct-2argument-constrained_extension-equal_arguments-1distinct_use.swift @@ -77,36 +77,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* [[TYPE_1]] to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* [[TYPE_2]] to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { -// CHECK-SAME: %swift.type* getelementptr inbounds ( -// CHECK-SAME: %swift.full_type, -// CHECK-SAME: %swift.full_type* bitcast ( -// CHECK-SAME: <{ -// CHECK-SAME: i8**, -// CHECK-SAME: [[INT]], -// CHECK-SAME: %swift.type_descriptor*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: %swift.type*, -// CHECK-SAME: i32, -// CHECK-SAME: {{(\[4 x i8\],)?}} -// CHECK-SAME: i64 -// CHECK-SAME: }>* @"$s4main9NamespaceVAAq_RszrlE5ValueVyS2i_SSGMf" -// CHECK-SAME: to %swift.full_type* -// CHECK-SAME: ), -// CHECK-SAME: i32 0, -// CHECK-SAME: i32 1 -// CHECK-SAME: ), -// CHECK-SAME: [[INT]] 0 -// CHECK-SAME: } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata( // CHECK-SAME: [[INT]] %0, // CHECK-SAME: i8* [[ERASED_TYPE_1]], diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift index eba0602f76ed8..f05de23860d43 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-1distinct_use.swift @@ -47,16 +47,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift index 4e862e3793f8b..ecd49ed9f9acd 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-2distinct_use.swift @@ -68,24 +68,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift index c3ca169770277..76c86eeca2c56 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-3distinct_use.swift @@ -89,32 +89,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_3_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3_1]] -// CHECK: [[EQUAL_TYPE_3_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_3_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_3_1]], [[EQUAL_TYPE_3_2]] -// CHECK: br i1 [[EQUAL_TYPES_3_2]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySSSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift index 47ba39cc3dd87..2f3d4fb8f9fd3 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-4distinct_use.swift @@ -110,40 +110,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_3_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3_1]] -// CHECK: [[EQUAL_TYPE_3_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_3_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_3_1]], [[EQUAL_TYPE_3_2]] -// CHECK: br i1 [[EQUAL_TYPES_3_2]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_4_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4_1]] -// CHECK: [[EQUAL_TYPE_4_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_4_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_4_1]], [[EQUAL_TYPE_4_2]] -// CHECK: br i1 [[EQUAL_TYPES_4_2]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySSSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys5UInt8VSSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift index d71408f206a8a..e0b53ad251296 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-5distinct_use.swift @@ -184,48 +184,6 @@ doit() // CHECK: entry: // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: br i1 [[EQUAL_TYPES_1_2]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[TYPE_COMPARISON_2:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_2]]: -// CHECK: [[EQUAL_TYPE_2_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_2_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_2_1]] -// CHECK: [[EQUAL_TYPE_2_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_2_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_2_1]], [[EQUAL_TYPE_2_2]] -// CHECK: br i1 [[EQUAL_TYPES_2_2]], label %[[EXIT_PRESPECIALIZED_2:[0-9]+]], label %[[TYPE_COMPARISON_3:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_3]]: -// CHECK: [[EQUAL_TYPE_3_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_3_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_3_1]] -// CHECK: [[EQUAL_TYPE_3_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_3_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_3_1]], [[EQUAL_TYPE_3_2]] -// CHECK: br i1 [[EQUAL_TYPES_3_2]], label %[[EXIT_PRESPECIALIZED_3:[0-9]+]], label %[[TYPE_COMPARISON_4:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_4]]: -// CHECK: [[EQUAL_TYPE_4_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_4_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_4_1]] -// CHECK: [[EQUAL_TYPE_4_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_4_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_4_1]], [[EQUAL_TYPE_4_2]] -// CHECK: br i1 [[EQUAL_TYPES_4_2]], label %[[EXIT_PRESPECIALIZED_4:[0-9]+]], label %[[TYPE_COMPARISON_5:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_5]]: -// CHECK: [[EQUAL_TYPE_5_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss4Int8VN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_5_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_5_1]] -// CHECK: [[EQUAL_TYPE_5_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$ss5UInt8VN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_5_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_5_1]], [[EQUAL_TYPE_5_2]] -// CHECK: br i1 [[EQUAL_TYPES_5_2]], label %[[EXIT_PRESPECIALIZED_5:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVyS2iGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_2]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySdSiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_3]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVySSSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_4]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys5UInt8VSSGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_PRESPECIALIZED_5]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main5ValueVys4Int8Vs5UInt8VGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift index 670d11205f865..1ebeb321ede26 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-2argument-within-class-1argument-1distinct_use.swift @@ -50,18 +50,6 @@ doit() // CHECK: [[ERASED_TYPE_1:%[0-9]+]] = bitcast %swift.type* %1 to i8* // CHECK: [[ERASED_TYPE_2:%[0-9]+]] = bitcast %swift.type* %2 to i8* // CHECK: [[ERASED_TYPE_3:%[0-9]+]] = bitcast %swift.type* %3 to i8* -// CHECK: br label %[[TYPE_COMPARISON_1:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_1]]: -// CHECK: [[EQUAL_TYPE_1_1:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSSN" to i8*), [[ERASED_TYPE_1]] -// CHECK: [[EQUAL_TYPES_1_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1_1]] -// CHECK: [[EQUAL_TYPE_1_2:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE_2]] -// CHECK: [[EQUAL_TYPES_1_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_1]], [[EQUAL_TYPE_1_2]] -// CHECK: [[EQUAL_TYPE_1_3:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSdN" to i8*), [[ERASED_TYPE_3]] -// CHECK: [[EQUAL_TYPES_1_3:%[0-9]+]] = and i1 [[EQUAL_TYPES_1_2]], [[EQUAL_TYPE_1_3]] -// CHECK: br i1 [[EQUAL_TYPES_1_3]], label %[[EXIT_PRESPECIALIZED_1:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED_1]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, %swift.type*, %swift.type*, i32, i32, i64 }>* @"$s4main9NamespaceC5ValueVySS_SiSdGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE_1]], i8* [[ERASED_TYPE_2]], i8* [[ERASED_TYPE_3]], %swift.type_descriptor* bitcast ({{.+}}$s4main9NamespaceC5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } diff --git a/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift index e02b67617cea8..99d00c6711936 100644 --- a/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-public-inmodule-1argument-1distinct_use.swift @@ -45,14 +45,6 @@ doit() // CHECK: define{{( protected| dllexport)?}} swiftcc %swift.metadata_response @"$s4main5ValueVMa"([[INT]] %0, %swift.type* %1) #{{[0-9]+}} { // CHECK: entry: // CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8* -// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]] -// CHECK: [[TYPE_COMPARISON_LABEL]]: -// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] -// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] -// CHECK: [[EXIT_PRESPECIALIZED]]: -// CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } -// CHECK: [[EXIT_NORMAL]]: // CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast ({{.+}}$s4main5ValueVMn{{.+}} to %swift.type_descriptor*)) #{{[0-9]+}} // CHECK: ret %swift.metadata_response {{%[0-9]+}} // CHECK: } From 409bc9d14f424e49ca3483f7e9e4c500ac904412 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 14 Aug 2020 10:10:06 -0700 Subject: [PATCH 152/663] [Test] Specify vendor rather than listing OSes. --- ...-1argument-1distinct_use-struct-outmodule-othermodule.swift | 3 +-- ...e-1argument-1distinct_use-struct-outmodule-samemodule.swift | 2 +- ...rg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift | 2 +- ...module_samemodule-2arg_protocol_outmodule_othermodule.swift | 2 +- ...tmodule_samemodule-2arg_protocol_outmodule_samemodule.swift | 2 +- ...1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift | 2 +- ...utmodule_samemodule-2arg_struct_outmodule_othermodule.swift | 2 +- ...outmodule_samemodule-2arg_struct_outmodule_samemodule.swift | 2 +- ...module-frozen-1argument-1distinct_use-struct-inmodule.swift | 2 +- ...ent-1distinct_use-struct-outmodule-frozen-othermodule.swift | 2 +- ...ment-1distinct_use-struct-outmodule-frozen-samemodule.swift | 2 +- ...-1distinct_use-struct-outmodule-resilient-othermodule.swift | 2 +- ...t-1distinct_use-struct-outmodule-resilient-samemodule.swift | 2 +- ...ule-resilient-1argument-1distinct_use-struct-inmodule.swift | 2 +- ...ent-1distinct_use-struct-outmodule-frozen-othermodule.swift | 2 +- ...ment-1distinct_use-struct-outmodule-frozen-samemodule.swift | 2 +- ...-1argument-1distinct_use-struct-outmodule-othermodule.swift | 2 +- ...-1distinct_use-struct-outmodule-resilient-othermodule.swift | 2 +- ...t-1distinct_use-struct-outmodule-resilient-samemodule.swift | 2 +- 19 files changed, 19 insertions(+), 20 deletions(-) diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift index 9e7d63dcd6af4..b870255458401 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-othermodule.swift @@ -3,12 +3,11 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios -// CHECK-NOT: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = // CHECK: @"$s7Generic11OneArgumentVy0C07IntegerVGMN" = linkonce_odr hidden constant <{ // CHECK-SAME: i8**, // CHECK-SAME: [[INT]], diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift index 2e99516a2171d..7eb0f7a6cbc60 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-1argument-1distinct_use-struct-outmodule-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift index 01fd6ddbbe2e0..7c7b6fee27917 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_inmodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument-1constraint.swift %S/Inputs/protocol-public-empty.swift %S/Inputs/struct-public-nonfrozen-0argument.swift %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift index ef6073aa7b01c..72abaf85836c3 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -DIMPORT_MODULE -L %t -I %t -lModule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lModule -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift index 6991186ef1aae..fa2a5a13b909b 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_protocol_outmodule_samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument-1constraint.swift %S/Inputs/protocol-public-empty.swift %S/Inputs/struct-public-nonfrozen-0argument.swift %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift index 8eb393cff6030..27e8384319d0e 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_inmodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument-1constraint.swift %S/Inputs/struct-public-nonfrozen-0argument.swift %S/Inputs/protocol-public-empty.swift -emit-library -o %t/%target-library-name(Module) -emit-module -module-name Module -emit-module-path %t/Module.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s %S/Inputs/main.swift %S/Inputs/struct-public-nonfrozen-0argument-conformance-empty.swift -module-name main -L %t -I %t -lModule -DIMPORT_MODULE | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift index 3e2bd95dc0601..274c6720d5d4f 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift index cd9fe461106bf..969903ee58540 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-2argument-1du-1arg_struct_outmodule_samemodule-2arg_struct_outmodule_samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-2argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift index 1a265a9b0f50e..d7aa427dc3a29 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-inmodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-1argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift index d89d0e0766170..7c5fff2d942b0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift index 5953b4c083fd1..c04ed4041ee8b 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-1argument.swift %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift index ea1bea95dedea..f74fe5876a098 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift index d22e9c5cd0b6c..996489fc04bce 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-frozen-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-1argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift index 61c1b5ad442c9..6771fb3b0cd83 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-inmodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift index 134583e4f087f..e5208842c7af0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift index e39afa70a6c25..bba412fdb884c 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-frozen-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift %S/Inputs/struct-public-frozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift index 1e22b5a2e2881..40f664a6485c5 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift index 6748988669cfc..30f5516f3e4e0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-othermodule.swift @@ -3,7 +3,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Argument) -emit-module -module-name Argument -emit-module-path %t/Argument.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric -lArgument | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift index 82a8faad31f3a..13e49953570e0 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-resilient-1argument-1distinct_use-struct-outmodule-resilient-samemodule.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -prespecialize-generic-metadata -target %module-target-future %S/Inputs/struct-public-nonfrozen-1argument.swift %S/Inputs/struct-public-nonfrozen-0argument.swift -emit-library -o %t/%target-library-name(Generic) -emit-module -module-name Generic -emit-module-path %t/Generic.swiftmodule -enable-library-evolution // RUN: %swift -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -L %t -I %t -lGeneric | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu +// REQUIRES: VENDOR=apple || OS=linux-gnu // UNSUPPORTED: CPU=i386 && OS=ios // UNSUPPORTED: CPU=armv7 && OS=ios // UNSUPPORTED: CPU=armv7s && OS=ios From 3edf8e16dea1739b86174c4e54a3ead13ca12693 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 14 Aug 2020 10:27:26 -0700 Subject: [PATCH 153/663] [metadata prespecialization] Bump availability. Previously, the availability was 5.3. Since compareProtocolConformanceDescriptors was added in 5.4 and was used by metadata accessors with baked-in checks for arguments which matched prespecializations, 5.3 was incorrect. Moreover, now that the searching for matches is done by getGenericMetadata, the metadata accessors no longer contain the early exits, so running against a 5.3 runtime would entail the metadata accessor failing to produce canonical prespecialized records. Here, the availability is bumped to 5.4 which includes the runtime changes to support the metadata accessors not having early exits to return prespecialized records. --- include/swift/AST/ASTContext.h | 4 ++++ lib/AST/Availability.cpp | 12 ++++++++---- test/IRGen/generic_metatypes_future.swift | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index e3745be52d7b2..9ef666affbf7e 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -669,6 +669,10 @@ class ASTContext final { /// compiler for the target platform. AvailabilityContext getSwift53Availability(); + /// Get the runtime availability of features introduced in the Swift 5.4 + /// compiler for the target platform. + AvailabilityContext getSwift54Availability(); + /// Get the runtime availability of features that have been introduced in the /// Swift compiler for future versions of the target platform. AvailabilityContext getSwiftFutureAvailability(); diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index a28946dc49bc4..743d3f80c69fb 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -306,21 +306,21 @@ AvailabilityContext ASTContext::getTypesInAbstractMetadataStateAvailability() { } AvailabilityContext ASTContext::getPrespecializedGenericMetadataAvailability() { - return getSwift53Availability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getCompareTypeContextDescriptorsAvailability() { - return getSwiftFutureAvailability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getCompareProtocolConformanceDescriptorsAvailability() { - return getSwiftFutureAvailability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getIntermodulePrespecializedGenericMetadataAvailability() { - return getSwiftFutureAvailability(); + return getSwift54Availability(); } AvailabilityContext ASTContext::getSwift52Availability() { @@ -384,6 +384,10 @@ AvailabilityContext ASTContext::getSwift53Availability() { } } +AvailabilityContext ASTContext::getSwift54Availability() { + return getSwiftFutureAvailability(); +} + AvailabilityContext ASTContext::getSwiftFutureAvailability() { auto target = LangOpts.Target; diff --git a/test/IRGen/generic_metatypes_future.swift b/test/IRGen/generic_metatypes_future.swift index bf18d17617de0..685eaed727377 100644 --- a/test/IRGen/generic_metatypes_future.swift +++ b/test/IRGen/generic_metatypes_future.swift @@ -1,5 +1,5 @@ -// RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-macosx50.99 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s +// RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-macosx99.99 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s // RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-ios99.0 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s // RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target x86_64-apple-tvos99.0 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 -DINT=i64 %s // RUN: %swift -prespecialize-generic-metadata -module-name generic_metatypes -target i386-apple-watchos9.99 -emit-ir -disable-legacy-type-info -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 -DINT=i32 %s From dc8bc70f2df7d050e3be0c230d2ac03898a44604 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Fri, 14 Aug 2020 11:37:21 -0700 Subject: [PATCH 154/663] [SIL] NFC: add header guard to SILInstructionWorklist.h. (#33460) --- include/swift/SIL/SILInstructionWorklist.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/swift/SIL/SILInstructionWorklist.h b/include/swift/SIL/SILInstructionWorklist.h index 9f4b399b60f4a..6df8e06cc0d5b 100644 --- a/include/swift/SIL/SILInstructionWorklist.h +++ b/include/swift/SIL/SILInstructionWorklist.h @@ -30,6 +30,9 @@ /// //===----------------------------------------------------------------------===// +#ifndef SWIFT_SIL_SILINSTRUCTIONWORKLIST_H +#define SWIFT_SIL_SILINSTRUCTIONWORKLIST_H + #include "swift/Basic/BlotSetVector.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" @@ -342,3 +345,5 @@ class SmallSILInstructionWorklist final }; } // end namespace swift + +#endif // SWIFT_SIL_SILINSTRUCTIONWORKLIST_H From 9b29ec6b9878c74b0482807e38ccc74550b6cd82 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Fri, 14 Aug 2020 09:36:08 -0700 Subject: [PATCH 155/663] IRGen: Store scalars as bytes to avoid undefined bits Don't tempt llvm to misbehave on partially initialized bytes -- it will. rdar:///66701259 --- lib/IRGen/ScalarTypeInfo.h | 28 +++++++++++++++++++--- test/IRGen/builtins.swift | 43 +++++++++++++++++++++------------- test/IRGen/enum.sil | 20 ++++++++++++---- test/IRGen/enum_future.sil | 20 ++++++++++++---- test/Interpreter/enum.swift | 46 +++++++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 29 deletions(-) diff --git a/lib/IRGen/ScalarTypeInfo.h b/lib/IRGen/ScalarTypeInfo.h index e3b0f3d03405b..4f9b843575580 100644 --- a/lib/IRGen/ScalarTypeInfo.h +++ b/lib/IRGen/ScalarTypeInfo.h @@ -117,10 +117,33 @@ class SingleScalarTypeInfo : public ScalarTypeInfo { schema.add(ExplosionSchema::Element::forScalar(ty)); } + void storeAsBytes(IRGenFunction &IGF, Explosion &src, Address addr) const { + auto &IGM = IGF.IGM; + + // Store in multiples of bytes to avoid undefined bits. + auto storageTy = addr.getAddress()->getType()->getPointerElementType(); + if (storageTy->isIntegerTy() && (storageTy->getIntegerBitWidth() % 8)) { + auto &Builder = IGF.Builder; + auto nextByteSize = (storageTy->getIntegerBitWidth() + 7) & ~7UL; + auto nextByteSizedIntTy = + llvm::IntegerType::get(IGM.getLLVMContext(), nextByteSize); + auto newAddr = + Address(Builder.CreatePointerCast(addr.getAddress(), + nextByteSizedIntTy->getPointerTo()), + addr.getAlignment()); + auto newValue = Builder.CreateZExt(src.claimNext(), nextByteSizedIntTy); + Builder.CreateStore(newValue, newAddr); + return; + } + + IGF.Builder.CreateStore(src.claimNext(), addr); + } + void initialize(IRGenFunction &IGF, Explosion &src, Address addr, bool isOutlined) const override { addr = asDerived().projectScalar(IGF, addr); - IGF.Builder.CreateStore(src.claimNext(), addr); + + storeAsBytes(IGF, src, addr); } void loadAsCopy(IRGenFunction &IGF, Address addr, @@ -149,8 +172,7 @@ class SingleScalarTypeInfo : public ScalarTypeInfo { } // Store. - llvm::Value *newValue = src.claimNext(); - IGF.Builder.CreateStore(newValue, dest); + storeAsBytes(IGF, src, dest); // Release the old value if we need to. if (!Derived::IsScalarPOD) { diff --git a/test/IRGen/builtins.swift b/test/IRGen/builtins.swift index d2dbff0b194c9..43adb03237981 100644 --- a/test/IRGen/builtins.swift +++ b/test/IRGen/builtins.swift @@ -235,21 +235,24 @@ func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32) // CHECK: [[Z_VAL:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 0 // CHECK: [[Z_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 1 // CHECK: store i32 [[Z_VAL]], i32* {{.*}}, align 4 - // CHECK: store i1 [[Z_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[Z_SUCCESS_B:%.*]] = zext i1 [[Z_SUCCESS]] to i8 + // CHECK: store i8 [[Z_SUCCESS_B]], i8* {{.*}}, align 1 var (z, zSuccess) = Builtin.cmpxchg_acquire_acquire_Int32(ptr, a, b) // CHECK: [[Y_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} monotonic monotonic // CHECK: [[Y_VAL:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 0 // CHECK: [[Y_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 1 // CHECK: store i32 [[Y_VAL]], i32* {{.*}}, align 4 - // CHECK: store i1 [[Y_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[Y_SUCCESS_B:%.*]] = zext i1 [[Y_SUCCESS]] to i8 + // CHECK: store i8 [[Y_SUCCESS_B]], i8* {{.*}}, align 1 var (y, ySuccess) = Builtin.cmpxchg_monotonic_monotonic_volatile_Int32(ptr, a, b) // CHECK: [[X_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} syncscope("singlethread") acquire monotonic // CHECK: [[X_VAL:%.*]] = extractvalue { i32, i1 } [[X_RES]], 0 // CHECK: [[X_SUCCESS:%.*]] = extractvalue { i32, i1 } [[X_RES]], 1 // CHECK: store i32 [[X_VAL]], i32* {{.*}}, align 4 - // CHECK: store i1 [[X_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[X_SUCCESS_B:%.*]] = zext i1 [[X_SUCCESS]] to i8 + // CHECK: store i8 [[X_SUCCESS_B]], i8* {{.*}}, align 1 var (x, xSuccess) = Builtin.cmpxchg_acquire_monotonic_volatile_singlethread_Int32(ptr, a, b) // CHECK: [[W_RES:%.*]] = cmpxchg volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst @@ -257,7 +260,8 @@ func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32) // CHECK: [[W_SUCCESS:%.*]] = extractvalue { i64, i1 } [[W_RES]], 1 // CHECK: [[W_VAL_PTR:%.*]] = inttoptr i64 [[W_VAL]] to i8* // CHECK: store i8* [[W_VAL_PTR]], i8** {{.*}}, align 8 - // CHECK: store i1 [[W_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[W_SUCCESS_B:%.*]] = zext i1 [[W_SUCCESS]] to i8 + // CHECK: store i8 [[W_SUCCESS_B]], i8* {{.*}}, align 1 var (w, wSuccess) = Builtin.cmpxchg_seqcst_seqcst_volatile_singlethread_RawPointer(ptr, ptr, ptr) // CHECK: [[V_RES:%.*]] = cmpxchg weak volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst @@ -265,7 +269,8 @@ func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32) // CHECK: [[V_SUCCESS:%.*]] = extractvalue { i64, i1 } [[V_RES]], 1 // CHECK: [[V_VAL_PTR:%.*]] = inttoptr i64 [[V_VAL]] to i8* // CHECK: store i8* [[V_VAL_PTR]], i8** {{.*}}, align 8 - // CHECK: store i1 [[V_SUCCESS]], i1* {{.*}}, align 1 + // CHECK: [[V_SUCCESS_B:%.*]] = zext i1 [[V_SUCCESS]] to i8 + // CHECK: store i8 [[V_SUCCESS_B]], i8* {{.*}}, align 1 var (v, vSuccess) = Builtin.cmpxchg_seqcst_seqcst_weak_volatile_singlethread_RawPointer(ptr, ptr, ptr) } @@ -558,7 +563,8 @@ struct Pair { var i: Int, b: Bool } // CHECK: [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0 // CHECK: store i32 0, i32* [[FLDI]] // CHECK: [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1 -// CHECK: store i1 false, i1* [[FLDB]] +// CHECK: [[BYTE_ADDR:%.*]] = bitcast i1* [[FLDB]] to i8* +// CHECK: store i8 0, i8* [[BYTE_ADDR]] // CHECK: [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0 // CHECK: [[RES:%.*]] = load i64, i64* [[RET]] // CHECK: ret i64 [[RES]] @@ -575,7 +581,8 @@ func zeroInitializer() -> (Empty, Pair) { // CHECK: [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0 // CHECK: store i32 0, i32* [[FLDI]] // CHECK: [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1 -// CHECK: store i1 false, i1* [[FLDB]] +// CHECK: [[BYTE_ADDR:%.*]] = bitcast i1* [[FLDB]] to i8* +// CHECK: store i8 0, i8* [[BYTE_ADDR]] // CHECK: [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0 // CHECK: [[RES:%.*]] = load i64, i64* [[RET]] // CHECK: ret i64 [[RES]] @@ -695,14 +702,16 @@ func generic_ispod_test(_: T) { // CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]] // CHECK-NEXT: [[ISNOTPOD:%.*]] = and i32 [[FLAGS]], 65536 // CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i32 [[ISNOTPOD]], 0 - // CHECK-NEXT: store i1 [[ISPOD]], i1* [[S:%.*]] + // CHECK-NEXT: [[BYTE_ADDR:%.*]] = bitcast i1* [[S:%.*]] to i8* + // CHECK-NEXT: [[BYTE:%.*]] = zext i1 [[ISPOD]] to i8 + // CHECK-NEXT: store i8 [[BYTE]], i8* [[BYTE_ADDR]] var s = Builtin.ispod(T.self) } // CHECK-LABEL: define {{.*}} @{{.*}}ispod_test func ispod_test() { - // CHECK: store i1 true, i1* - // CHECK: store i1 false, i1* + // CHECK: store i8 1, i8* + // CHECK: store i8 0, i8* var t = Builtin.ispod(Int.self) var f = Builtin.ispod(Builtin.NativeObject.self) } @@ -713,17 +722,19 @@ func generic_isbitwisetakable_test(_: T) { // CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]] // CHECK-NEXT: [[ISNOTBITWISETAKABLE:%.*]] = and i32 [[FLAGS]], 1048576 // CHECK-NEXT: [[ISBITWISETAKABLE:%.*]] = icmp eq i32 [[ISNOTBITWISETAKABLE]], 0 - // CHECK-NEXT: store i1 [[ISBITWISETAKABLE]], i1* [[S:%.*]] + // CHECK-NEXT: [[BYTE_ADDR:%.*]] = bitcast i1* [[S:%.*]] + // CHECK-NEXT: [[BYTE:%.*]] = zext i1 [[ISBITWISETAKABLE]] to i8 + // CHECK-NEXT: store i8 [[BYTE]], i8* [[BYTE_ADDR]] var s = Builtin.isbitwisetakable(T.self) } // CHECK-LABEL: define {{.*}} @{{.*}}isbitwisetakable_test func isbitwisetakable_test() { - // CHECK: store i1 true, i1* - // CHECK: store i1 true, i1* - // CHECK: store i1 true, i1* - // CHECK: store i1 true, i1* - // CHECK: store i1 false, i1* + // CHECK: store i8 1, i8* + // CHECK: store i8 1, i8* + // CHECK: store i8 1, i8* + // CHECK: store i8 1, i8* + // CHECK: store i8 0, i8* var t1 = Builtin.isbitwisetakable(Int.self) var t2 = Builtin.isbitwisetakable(C.self) var t3 = Builtin.isbitwisetakable(Abc.self) diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil index b08f0e6587bfd..f17d1036ab376 100644 --- a/test/IRGen/enum.sil +++ b/test/IRGen/enum.sil @@ -1010,7 +1010,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[T:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %1 to i63* -// CHECK-64: store i63 [[T]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i63 [[T]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: ret void // CHECK-64: } sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () { @@ -1784,7 +1786,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -1825,7 +1829,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i63* -// CHECK-64: store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -2024,7 +2030,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF @@ -2060,7 +2068,9 @@ entry(%0 : $Builtin.Int60): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i60* -// CHECK-64: store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i60* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF diff --git a/test/IRGen/enum_future.sil b/test/IRGen/enum_future.sil index b538b63093269..48cc72ee09922 100644 --- a/test/IRGen/enum_future.sil +++ b/test/IRGen/enum_future.sil @@ -1014,7 +1014,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[T:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future21SinglePayloadSpareBitO* %1 to i63* -// CHECK-64: store i63 [[T]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[BYTE:%.*]] = zext i63 [[T]] to i64 +// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]] // CHECK-64: ret void // CHECK-64: } sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () { @@ -1788,7 +1790,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -1829,7 +1833,9 @@ entry(%0 : $Builtin.Int63): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i63* -// CHECK-64: store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x7FFF_FFFF_FFFF_FFFF @@ -2028,7 +2034,9 @@ entry(%0 : $Builtin.Int62): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i62* -// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF @@ -2064,7 +2072,9 @@ entry(%0 : $Builtin.Int60): // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60 // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i60* -// CHECK-64: store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]] +// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i60* [[DATA_ADDR]] to i64* +// CHECK-64: [[VAL:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64 +// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]] // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i64* // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] // -- 0x3FFF_FFFF_FFFF_FFFF diff --git a/test/Interpreter/enum.swift b/test/Interpreter/enum.swift index da9f6c4b17cf6..b2b66b761e743 100644 --- a/test/Interpreter/enum.swift +++ b/test/Interpreter/enum.swift @@ -698,3 +698,49 @@ func testCase() { // CHECK: Container(storage: a.MultiIndirectRef.ind(5)) testCase() + + +enum BitEnum { + case first + case second +} +protocol Init { + init() +} +struct TrailingByte : Init { + var x = 2 + var y = BitEnum.first + init() { + x = 2 + y = BitEnum.first + } +} + +@inline(never) +func capture(_ t: inout T) { + print("captured \(t)") +} + +@inline(never) +func reproduction(_ x: Int, _ y: Int, _ t: T) { + var o : Optional = nil + + + for i in 0 ..< x { + if i == y { + o = T() + } + } + + capture(&o) + + if var byte = o { + print("there is a byte (failure)") + print(byte) + } else { + print("there is no byte") + } +} + +// CHECK: there is no byte +reproduction(2, 3, TrailingByte()) From cb537b41fb3b7563bb9ebb71f14cd76fdf5e303a Mon Sep 17 00:00:00 2001 From: Marcel Hlopko Date: Fri, 14 Aug 2020 20:51:16 +0200 Subject: [PATCH 156/663] [cxx-interop] Import `typedef`-ed template instantiations #32950 (#33451) This is a roll-forward of https://github.com/apple/swift/pull/32950, with explicit c++17 version removed from tests. This is not needed since C++17 is the default anyway. -- In this PR we teach `ClangImporter` to import typedef statements with template instantiation as its underlying type. ```c++ template struct MagicWrapper { T t; }; struct MagicNumber {}; typedef MagicWrapper WrappedMagicNumber; ``` will be made available in Swift as if `WrappedMagicNumber` is a regular struct. In C++, multiple distinct typedeffed instantiations resolve to the same canonical type. We implement this by creating a hidden intermediate struct that typedef aliasses. The struct is named as `__CxxTemplateInst` plus Itanium mangled type of the instantiation. For the example above the name of the hidden struct is `__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Double underscore (denoting a reserved C++ identifier) is used to discourage direct usage. We chose Itanium mangling scheme because it produces valid Swift identifiers and covers all C++ edge cases. Imported module interface of the example above: ```swift struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { var t: MagicNumber } struct MagicNumber {} typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE ``` We modified the `SwiftLookupTable` logic to show hidden structs in `swift_ide_test` for convenience. Co-authored-by: Rosica Dejanovska Co-authored-by: Dmitri Gribenko Co-authored-by: Robert Widmann --- docs/ABI/Mangling.rst | 37 ++++++++++++++++ docs/CppInteroperabilityManifesto.md | 42 ++++++++++++++++++- include/swift/Strings.h | 4 ++ lib/AST/ASTMangler.cpp | 9 ++++ lib/ClangImporter/ImportDecl.cpp | 29 ++++++++++--- lib/ClangImporter/ImportName.cpp | 30 +++++++++++++ lib/ClangImporter/SwiftLookupTable.cpp | 23 +++++++++- test/Demangle/Inputs/manglings.txt | 2 + .../Cxx/templates/Inputs/canonical-types.h | 18 ++++++++ .../decl-with-definition-including-members.h | 26 ++++++++++++ .../templates/Inputs/decl-with-definition.h | 24 +++++++++++ .../Inputs/decl-with-primitive-argument.h | 12 ++++++ .../Inputs/decl-without-definition.h | 20 +++++++++ .../Inputs/eager-instantiation-problems.h | 24 +++++++++++ .../Inputs/explicit-specialization.h | 29 +++++++++++++ ...kage-of-swift-symbols-for-imported-types.h | 21 ++++++++++ test/Interop/Cxx/templates/Inputs/mangling.h | 11 +++++ .../Cxx/templates/Inputs/module.modulemap | 39 +++++++++++++++++ .../Cxx/templates/Inputs/using-directive.h | 17 ++++++++ .../canonical-types-module-interface.swift | 15 +++++++ .../Cxx/templates/canonical-types.swift | 15 +++++++ ...cl-with-definition-including-members.swift | 16 +++++++ .../decl-with-definition-irgen.swift | 33 +++++++++++++++ .../decl-with-definition-silgen.swift | 21 ++++++++++ .../Cxx/templates/decl-with-definition.swift | 16 +++++++ .../decl-with-primitive-argument.swift | 15 +++++++ ...-without-definition-module-interface.swift | 15 +++++++ .../templates/decl-without-definition.swift | 16 +++++++ .../eager-instatiation-problems.swift | 32 ++++++++++++++ .../templates/explicit-specialization.swift | 20 +++++++++ ...ift-symbols-for-imported-types-irgen.swift | 28 +++++++++++++ .../Cxx/templates/mangling-irgen.swift | 20 +++++++++ .../Cxx/templates/mangling-silgen.swift | 20 +++++++++ .../using-directive-module-interface.swift | 15 +++++++ .../Cxx/templates/using-directive.swift | 16 +++++++ test/lit.cfg | 3 +- 36 files changed, 724 insertions(+), 9 deletions(-) create mode 100644 test/Interop/Cxx/templates/Inputs/canonical-types.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-definition.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h create mode 100644 test/Interop/Cxx/templates/Inputs/decl-without-definition.h create mode 100644 test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h create mode 100644 test/Interop/Cxx/templates/Inputs/explicit-specialization.h create mode 100644 test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h create mode 100644 test/Interop/Cxx/templates/Inputs/mangling.h create mode 100644 test/Interop/Cxx/templates/Inputs/module.modulemap create mode 100644 test/Interop/Cxx/templates/Inputs/using-directive.h create mode 100644 test/Interop/Cxx/templates/canonical-types-module-interface.swift create mode 100644 test/Interop/Cxx/templates/canonical-types.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition-including-members.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition-irgen.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition-silgen.swift create mode 100644 test/Interop/Cxx/templates/decl-with-definition.swift create mode 100644 test/Interop/Cxx/templates/decl-with-primitive-argument.swift create mode 100644 test/Interop/Cxx/templates/decl-without-definition-module-interface.swift create mode 100644 test/Interop/Cxx/templates/decl-without-definition.swift create mode 100644 test/Interop/Cxx/templates/eager-instatiation-problems.swift create mode 100644 test/Interop/Cxx/templates/explicit-specialization.swift create mode 100644 test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift create mode 100644 test/Interop/Cxx/templates/mangling-irgen.swift create mode 100644 test/Interop/Cxx/templates/mangling-silgen.swift create mode 100644 test/Interop/Cxx/templates/using-directive-module-interface.swift create mode 100644 test/Interop/Cxx/templates/using-directive.swift diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index a65799b8c53cd..f35339c9ebb70 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -1107,3 +1107,40 @@ nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` mo .. code:: sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct + +Importing C++ class template instantiations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A class template instantiation is imported as a struct named +``__CxxTemplateInst`` plus Itanium mangled type of the instantiation (see the +``type`` production in the Itanium specification). Note that Itanium mangling is +used on all platforms, regardless of the ABI of the C++ toolchain, to ensure +that the mangled name is a valid Swift type name (this is not the case for MSVC +mangled names). A prefix with a double underscore (to ensure we have a reserved +C++ identifier) is added to limit the possibility for conflicts with names of +user-defined structs. The struct is notionally defined in the ``__C`` module, +similarly to regular C and C++ structs and classes. Consider the following C++ +module: + +.. code-block:: c++ + + template + struct MagicWrapper { + T t; + }; + + struct MagicNumber {}; + + typedef MagicWrapper WrappedMagicNumber; + +``WrappedMagicNumber`` is imported as a typealias for struct +``__CxxTemplateInst12MagicWrapperI11MagicNumberE``. Interface of the imported +module looks as follows: + +.. code-block:: swift + + struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { + var t: MagicNumber + } + struct MagicNumber {} + typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE diff --git a/docs/CppInteroperabilityManifesto.md b/docs/CppInteroperabilityManifesto.md index f3a8df51820d2..b23c914268c1b 100644 --- a/docs/CppInteroperabilityManifesto.md +++ b/docs/CppInteroperabilityManifesto.md @@ -67,6 +67,7 @@ Assumptions: + [Function templates: calls with generic type parameters](#function-templates-calls-with-generic-type-parameters) + [Function templates: importing as real generic functions](#function-templates-importing-as-real-generic-functions) + [Class templates](#class-templates) + + [Class templates: importing instantiation behind typedef](#class-templates-importing-instantiation-behind-typedef) + [Class templates: importing specific specilalizations](#class-templates-importing-specific-specilalizations) + [Class templates: using with generic type parameters](#class-templates-using-with-generic-type-parameters) + [Class templates: using in generic code through a synthesized protocol](#class-templates-using-in-generic-code-through-a-synthesized-protocol) @@ -2575,6 +2576,45 @@ We could ignore explicit specializations of function templates, because they don't affect the API. Explicit specializations of class templates can dramatically change the API of the type. +### Class templates: Importing full class template instantiations + +A class template instantiation could be imported as a struct named +`__CxxTemplateInst` plus Itanium mangled type of the instantiation (see the +`type` production in the Itanium specification). Note that Itanium mangling is +used on all platforms, regardless of the ABI of the C++ toolchain, to ensure +that the mangled name is a valid Swift type name (this is not the case for MSVC +mangled names). A prefix with a double underscore (to ensure we have a reserved +C++ identifier) is added to limit the possibility for conflicts with names of +user-defined structs. The struct is notionally defined in the `__C` module, +similarly to regular C and C++ structs and classes. Consider the following C++ +module: + +```c++ +// C++ header. + +template +struct MagicWrapper { + T t; +}; +struct MagicNumber {}; + +typedef MagicWrapper WrappedMagicNumber; +``` + +`WrappedMagicNumber` will be imported as a typealias for a struct +`__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Interface of the imported +module will look as follows: + +```swift +// C++ header imported to Swift. + +struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { + var t: MagicNumber +} +struct MagicNumber {} +typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE +``` + ### Class templates: importing specific specilalizations Just like with calls to C++ function templates, it is easy to compile a use of a @@ -2752,7 +2792,7 @@ func useConcrete() { ### Class templates: importing as real generic structs -If we know the complete set of allowed type arguments to a C++ function +If we know the complete set of allowed type arguments to a C++ struct template, we could import it as an actual Swift generic struct. Every method of that struct will perform dynamic dispatch based on type parameters. See the section about function templates for more details. diff --git a/include/swift/Strings.h b/include/swift/Strings.h index 32a7bb2d0072c..69b29ff4a52b9 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -38,6 +38,10 @@ constexpr static const StringLiteral MANGLING_MODULE_OBJC = "__C"; constexpr static const StringLiteral MANGLING_MODULE_CLANG_IMPORTER = "__C_Synthesized"; +/// The name prefix for C++ template instantiation imported as a Swift struct. +constexpr static const StringLiteral CXX_TEMPLATE_INST_PREFIX = + "__CxxTemplateInst"; + constexpr static const StringLiteral SEMANTICS_PROGRAMTERMINATION_POINT = "programtermination_point"; diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index e013ad5db8b3c..be1c4af4e0ea1 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -39,6 +39,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" @@ -2114,6 +2115,7 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { // Always use Clang names for imported Clang declarations, unless they don't // have one. auto tryAppendClangName = [this, decl]() -> bool { + auto *nominal = dyn_cast(decl); auto namedDecl = getClangDeclForMangling(decl); if (!namedDecl) return false; @@ -2126,6 +2128,13 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { appendIdentifier(interface->getObjCRuntimeNameAsString()); } else if (UseObjCRuntimeNames && protocol) { appendIdentifier(protocol->getObjCRuntimeNameAsString()); + } else if (auto ctsd = dyn_cast(namedDecl)) { + // If this is a `ClassTemplateSpecializationDecl`, it was + // imported as a Swift decl with `__CxxTemplateInst...` name. + // `ClassTemplateSpecializationDecl`'s name does not include information about + // template arguments, and in order to prevent name clashes we use the + // name of the Swift decl which does include template arguments. + appendIdentifier(nominal->getName().str()); } else { appendIdentifier(namedDecl->getName()); } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 7f40d1a6de44c..a67dd74a11eca 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3477,14 +3477,33 @@ namespace { Decl *VisitClassTemplateSpecializationDecl( const clang::ClassTemplateSpecializationDecl *decl) { - // FIXME: We could import specializations, but perhaps only as unnamed - // structural types. - return nullptr; + // `Sema::isCompleteType` will try to instantiate the class template as a + // side-effect and we rely on this here. `decl->getDefinition()` can + // return nullptr before the call to sema and return its definition + // afterwards. + if (!Impl.getClangSema().isCompleteType( + decl->getLocation(), + Impl.getClangASTContext().getRecordType(decl))) { + // If we got nullptr definition now it means the type is not complete. + // We don't import incomplete types. + return nullptr; + } + auto def = dyn_cast( + decl->getDefinition()); + assert(def && "Class template instantiation didn't have definition"); + // FIXME: This will instantiate all members of the specialization (and detect + // instantiation failures in them), which can be more than is necessary + // and is more than what Clang does. As a result we reject some C++ + // programs that Clang accepts. + Impl.getClangSema().InstantiateClassTemplateSpecializationMembers( + def->getLocation(), def, clang::TSK_ExplicitInstantiationDefinition); + + return VisitRecordDecl(def); } Decl *VisitClassTemplatePartialSpecializationDecl( - const clang::ClassTemplatePartialSpecializationDecl *decl) { - // Note: templates are not imported. + const clang::ClassTemplatePartialSpecializationDecl *decl) { + // Note: partial template specializations are not imported. return nullptr; } diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 1611d20507369..46817ce93de2a 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -31,8 +31,10 @@ #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Parser.h" +#include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Mangle.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" @@ -1698,6 +1700,34 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, } } + if (auto classTemplateSpecDecl = + dyn_cast(D)) { + if (!isa(D)) { + + auto &astContext = classTemplateSpecDecl->getASTContext(); + // Itanium mangler produces valid Swift identifiers, use it to generate a name for + // this instantiation. + clang::MangleContext *mangler = clang::ItaniumMangleContext::create( + astContext, astContext.getDiagnostics()); + llvm::SmallString<128> storage; + llvm::raw_svector_ostream buffer(storage); + mangler->mangleTypeName(astContext.getRecordType(classTemplateSpecDecl), + buffer); + + // The Itanium mangler does not provide a way to get the mangled + // representation of a type. Instead, we call mangleTypeName() that + // returns the name of the RTTI typeinfo symbol, and remove the _ZTS + // prefix. Then we prepend __CxxTemplateInst to reduce chances of conflict + // with regular C and C++ structs. + llvm::SmallString<128> mangledNameStorage; + llvm::raw_svector_ostream mangledName(mangledNameStorage); + assert(buffer.str().take_front(4) == "_ZTS"); + mangledName << CXX_TEMPLATE_INST_PREFIX << buffer.str().drop_front(4); + + baseName = swiftCtx.getIdentifier(mangledName.str()).get(); + } + } + // swift_newtype-ed declarations may have common words with the type name // stripped. if (auto newtypeDecl = findSwiftNewtype(D, clangSema, version)) { diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 74a64dcb025d5..3ac0d0fe45d0c 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1881,10 +1881,16 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table, // struct names when relevant, not just pointer names. That way we can check // both CFDatabase.def and the objc_bridge attribute and cover all our bases. if (auto *tagDecl = dyn_cast(named)) { - if (!tagDecl->getDefinition()) + // We add entries for ClassTemplateSpecializations that don't have + // definition. It's possible that the decl will be instantiated by + // SwiftDeclConverter later on. We cannot force instantiating + // ClassTemplateSPecializations here because we're currently writing the + // AST, so we cannot modify it. + if (!isa(named) && + !tagDecl->getDefinition()) { return; + } } - // If we have a name to import as, add this entry to the table. auto currentVersion = ImportNameVersion::fromOptions(nameImporter.getLangOpts()); @@ -2077,6 +2083,19 @@ void SwiftLookupTableWriter::populateTableWithDecl(SwiftLookupTable &table, // Add this entry to the lookup table. addEntryToLookupTable(table, named, nameImporter); + if (auto typedefDecl = dyn_cast(named)) { + if (auto typedefType = dyn_cast( + typedefDecl->getUnderlyingType())) { + if (auto CTSD = dyn_cast( + typedefType->getAsTagDecl())) { + // Adding template instantiation behind typedef as a top-level entry + // so the instantiation appears in the API. + assert(!isa(CTSD) && + "Class template partial specialization cannot appear behind typedef"); + addEntryToLookupTable(table, CTSD, nameImporter); + } + } + } } void SwiftLookupTableWriter::populateTable(SwiftLookupTable &table, diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 01591a1ab8530..f0b200e2979a9 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -365,3 +365,5 @@ $s0059xxxxxxxxxxxxxxx_ttttttttBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBee -> $s0059xxxx $sx1td_t ---> (t: A...) $s7example1fyyYF -> example.f() async -> () $s7example1fyyYKF -> example.f() async throws -> () +$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF ---> main.receiveInstantiation(inout __C.__CxxTemplateInst12MagicWrapperIiE) -> () +$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF ---> main.returnInstantiation() -> __C.__CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/Inputs/canonical-types.h b/test/Interop/Cxx/templates/Inputs/canonical-types.h new file mode 100644 index 0000000000000..865c85a882cf9 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/canonical-types.h @@ -0,0 +1,18 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +typedef MagicWrapper WrappedMagicNumberA; +typedef MagicWrapper WrappedMagicNumberB; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h new file mode 100644 index 0000000000000..4c772c9dfaca0 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h @@ -0,0 +1,26 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +inline int forceInstantiation() { + auto t = MagicWrapper(); + return t.getValuePlusArg(14); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition +// because function above forced the instantiation. Its members are fully +// instantiated, so nothing needs to be explicitly instantiated by the Swift +// compiler. +typedef MagicWrapper FullyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h new file mode 100644 index 0000000000000..d8fb7b56f676b --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h @@ -0,0 +1,24 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +inline MagicWrapper forceInstantiation() { + return MagicWrapper(); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper already has a definition +// because function above forced the instantiation. Its members are not +// instantiated though, the Swift compiler needs to instantiate them. +typedef MagicWrapper PartiallyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h new file mode 100644 index 0000000000000..2bba7d493e342 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h @@ -0,0 +1,12 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t + arg; } +}; + +typedef MagicWrapper WrappedMagicInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-without-definition.h b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h new file mode 100644 index 0000000000000..a4eb3506672b2 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h @@ -0,0 +1,20 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +// The ClassTemplateSpecializationDecl node for MagicWrapper doesn't have a +// definition in Clang because nothing in this header required the +// instantiation. Therefore, the Swift compiler must trigger instantiation. +typedef MagicWrapper MagicallyWrappedIntWithoutDefinition; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h new file mode 100644 index 0000000000000..5992054ae9d3d --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h @@ -0,0 +1,24 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H + +struct MagicNumber { + int getInt() const { return 42; } +}; + +template +struct MagicWrapper { + void callGetInt() const { + T::getIntDoesNotExist(); + } + + template int sfinaeGetInt(A a, decltype(&A::getInt)) { + return a.getInt(); + } + template int sfinaeGetInt(A a, ...) { + return -42; + } +}; + +typedef MagicWrapper BrokenMagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H diff --git a/test/Interop/Cxx/templates/Inputs/explicit-specialization.h b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h new file mode 100644 index 0000000000000..62b9f7aa030af --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h @@ -0,0 +1,29 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H + +struct SpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +struct NonSpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +template +struct MagicWrapper { + T t; + int doubleIfSpecializedElseTriple() const { return 3 * t.getValue(); } +}; + +template <> +struct MagicWrapper { + SpecializedIntWrapper t; + int doubleIfSpecializedElseTriple() const { return 2 * t.getValue(); } +}; + +typedef MagicWrapper WrapperWithSpecialization; +typedef MagicWrapper WrapperWithoutSpecialization; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H diff --git a/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h new file mode 100644 index 0000000000000..d700209d93873 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h @@ -0,0 +1,21 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H + +template +struct MagicWrapper { + T t; + int callGetInt() const { + return t.getInt() + 5; + } +}; + +struct MagicNumber { + // Swift runtime defines many value witness tables for types with some common layouts. + // This struct's uncommon size forces the compiler to define a new value witness table instead of reusing one from the runtime. + char forceVWTableCreation[57]; + int getInt() const { return 12; } +}; + +typedef MagicWrapper WrappedMagicNumber; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/mangling.h b/test/Interop/Cxx/templates/Inputs/mangling.h new file mode 100644 index 0000000000000..f135b52747600 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/mangling.h @@ -0,0 +1,11 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H + +template +struct MagicWrapper {}; + +typedef MagicWrapper WrappedMagicInt; +typedef MagicWrapper WrappedMagicBool; + + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H diff --git a/test/Interop/Cxx/templates/Inputs/module.modulemap b/test/Interop/Cxx/templates/Inputs/module.modulemap new file mode 100644 index 0000000000000..af6d28e675a40 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/module.modulemap @@ -0,0 +1,39 @@ +module DeclWithPrimitiveArgument { + header "decl-with-primitive-argument.h" +} + +module DeclWithoutDefinition { + header "decl-without-definition.h" +} + +module DeclWithDefinition { + header "decl-with-definition.h" +} + +module DeclWithDefinitionIncludingMembers { + header "decl-with-definition-including-members.h" +} + +module CanonicalTypes { + header "canonical-types.h" +} + +module ExplicitSpecialization { + header "explicit-specialization.h" +} + +module UsingDirective { + header "using-directive.h" +} + +module EagerInstantiationProblems { + header "eager-instantiation-problems.h" +} + +module Mangling { + header "mangling.h" +} + +module LinkageOfSwiftSymbolsForImportedTypes { + header "linkage-of-swift-symbols-for-imported-types.h" +} diff --git a/test/Interop/Cxx/templates/Inputs/using-directive.h b/test/Interop/Cxx/templates/Inputs/using-directive.h new file mode 100644 index 0000000000000..076660e8a19e4 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/using-directive.h @@ -0,0 +1,17 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +using UsingWrappedMagicNumber = MagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H diff --git a/test/Interop/Cxx/templates/canonical-types-module-interface.swift b/test/Interop/Cxx/templates/canonical-types-module-interface.swift new file mode 100644 index 0000000000000..3a90d1d44311a --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=CanonicalTypes -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias WrappedMagicNumberA = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK: typealias WrappedMagicNumberB = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/canonical-types.swift b/test/Interop/Cxx/templates/canonical-types.swift new file mode 100644 index 0000000000000..6f11ea61ca8e5 --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import CanonicalTypes +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("canonical-types") { + // Different typedefs with the same C++ canonical type must have the same type from Swift's perspective as well. + expectEqualType(WrappedMagicNumberA.self, WrappedMagicNumberB.self) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-including-members.swift b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift new file mode 100644 index 0000000000000..8c7dcf7013557 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithDefinitionIncludingMembers +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("fully-defined") { + let myInt = IntWrapper(value: 10) + var magicInt = FullyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 15) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift new file mode 100644 index 0000000000000..34825a34ce7e4 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift @@ -0,0 +1,33 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 7) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(13) +} + +// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main18getWrappedMagicInts5Int32VyF"() +// CHECK: %magicInt = alloca %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, align 4 +// CHECK: %magicInt.t = getelementptr inbounds %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt, i32 0, i32 0 +// CHECK: [[MAGIC_WRAPPER:%.*]] = bitcast %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt to %struct.MagicWrapper* +// CHECK: call i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* [[MAGIC_WRAPPER]], i32 13) + +// CHECK: define weak_odr{{( dso_local)?}} i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* %this, i32 %arg) +// CHECK: %this.addr = alloca %struct.MagicWrapper*, align {{4|8}} +// CHECK: store %struct.MagicWrapper* %this, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.MagicWrapper*, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %t = getelementptr inbounds %struct.MagicWrapper, %struct.MagicWrapper* %this1, i32 0, i32 0 +// CHECK: %call = call i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %t) +// CHECK: [[ARG:%.*]] = load i32, i32* %arg.addr, align 4 +// CHECK: %add = add nsw i32 %call, [[ARG]] +// CHECK: ret i32 %add + +// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %this) +// CHECK: %this.addr = alloca %struct.IntWrapper*, align {{4|8}} +// CHECK: store %struct.IntWrapper* %this, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.IntWrapper*, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %value = getelementptr inbounds %struct.IntWrapper, %struct.IntWrapper* %this1, i32 0, i32 0 +// CHECK: [[VALUE:%.*]] = load i32, i32* %value, align 4 +// CHECK: ret i32 [[VALUE]] diff --git a/test/Interop/Cxx/templates/decl-with-definition-silgen.swift b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift new file mode 100644 index 0000000000000..a9481f6ac9d6c --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift @@ -0,0 +1,21 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 21) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(32) +} + +// CHECK: // getWrappedMagicInt() +// CHECK: sil @$s4main18getWrappedMagicInts5Int32VyF : $@convention(thin) () -> Int32 { +// CHECK: [[INT_WRAPPER:%.*]] = struct $IntWrapper ([[_:%.*]] : $Int32) +// CHECK: [[_:%.*]] = struct $__CxxTemplateInst12MagicWrapperI10IntWrapperE ([[INT_WRAPPER]] : $IntWrapper) +// CHECK: // function_ref {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: [[_:%.*]] = function_ref @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 + +// CHECK: // {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: MagicWrapper::getValuePlusArg + +// CHECK: sil [clang __CxxTemplateInst12MagicWrapperI10IntWrapperE.getValuePlusArg] @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 diff --git a/test/Interop/Cxx/templates/decl-with-definition.swift b/test/Interop/Cxx/templates/decl-with-definition.swift new file mode 100644 index 0000000000000..3772cd4f7a99a --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("has-partial-definition") { + let myInt = IntWrapper(value: 32) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 37) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-primitive-argument.swift b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift new file mode 100644 index 0000000000000..951c49c0fb814 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithPrimitiveArgument +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("int-argument") { + var wrappedMagicInt = WrappedMagicInt(t: 42) + expectEqual(wrappedMagicInt.getValuePlusArg(5), 47) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift new file mode 100644 index 0000000000000..ca12841f96cb9 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=DeclWithoutDefinition -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias MagicallyWrappedIntWithoutDefinition = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/decl-without-definition.swift b/test/Interop/Cxx/templates/decl-without-definition.swift new file mode 100644 index 0000000000000..23eca83c31d85 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import DeclWithoutDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("without-definition") { + let myInt = IntWrapper(value: 17) + var magicInt = MagicallyWrappedIntWithoutDefinition(t: myInt) + expectEqual(magicInt.getValuePlusArg(11), 28) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/eager-instatiation-problems.swift b/test/Interop/Cxx/templates/eager-instatiation-problems.swift new file mode 100644 index 0000000000000..f341c8c68c87c --- /dev/null +++ b/test/Interop/Cxx/templates/eager-instatiation-problems.swift @@ -0,0 +1,32 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import EagerInstantiationProblems +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("eager-instantiation-of-members") { + // This will fail with: + // + // error: type 'int' cannot be used prior to '::' because it has no members + // T::getIntDoesNotExist(); + // + // whereas in C++ this compiles. This is caused by ClangImporter eagerly + // instantiating typedeffed templates and also their members. + // TODO(scentini): Fix this + // let _brokenMagicWrapper = BrokenMagicWrapper() +} + +TemplatesTestSuite.test("sfinae-example") { + // This will fail since we are currently not instantiating function templates. + // In C++ the first sfinaeGetInt should fail to instantiate, therefore get + // ignored, and only the second sfinaeGetInt is used. + // TODO(SR-12541): Fix this + // let magicNumber = MagicNumber() + // var brokenMagicWrapper = BrokenMagicWrapper() + // expectEqual(42, brokenMagicWrapper.sfinaeGetInt(magicNumber, 0)) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/explicit-specialization.swift b/test/Interop/Cxx/templates/explicit-specialization.swift new file mode 100644 index 0000000000000..b8e02faefe85b --- /dev/null +++ b/test/Interop/Cxx/templates/explicit-specialization.swift @@ -0,0 +1,20 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import ExplicitSpecialization +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("explicit-specialization") { + let specializedInt = SpecializedIntWrapper(value: 7) + var specializedMagicInt = WrapperWithSpecialization(t: specializedInt) + expectEqual(specializedMagicInt.doubleIfSpecializedElseTriple(), 14) + + let nonSpecializedInt = NonSpecializedIntWrapper(value: 7) + var nonSpecializedMagicInt = WrapperWithoutSpecialization(t: nonSpecializedInt) + expectEqual(nonSpecializedMagicInt.doubleIfSpecializedElseTriple(), 21) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift new file mode 100644 index 0000000000000..f3a2ae75d69ba --- /dev/null +++ b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift @@ -0,0 +1,28 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import LinkageOfSwiftSymbolsForImportedTypes + +public func forceValueWitnessTableCreation() -> Any { + let magicNumber = MagicNumber() + return WrappedMagicNumber(t: magicNumber) +} + +public func getMagicNumberForLinkageComparison() -> Any { + return MagicNumber() +} + +// CHECK: $sSo11MagicNumberVWV" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMn" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMf" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVML" = linkonce_odr hidden global + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVWV" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMn" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMf" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVML" = linkonce_odr hidden global + +// CHECK: $sSo11MagicNumberVMB" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMF" = linkonce_odr hidden constant + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMB" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMF" = linkonce_odr hidden constant diff --git a/test/Interop/Cxx/templates/mangling-irgen.swift b/test/Interop/Cxx/templates/mangling-irgen.swift new file mode 100644 index 0000000000000..c55feb8b5dc47 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-irgen.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func receiveInstantiation(_ i: inout WrappedMagicInt) {} + +// Don't forget to update manglings.txt when changing s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIiEV* nocapture dereferenceable(1) %0) + +public func receiveInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIbEV* nocapture dereferenceable(1) %0) + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// Don't forget to update manglings.txt when changing s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF"() + diff --git a/test/Interop/Cxx/templates/mangling-silgen.swift b/test/Interop/Cxx/templates/mangling-silgen.swift new file mode 100644 index 0000000000000..7d4cc6f7e3c39 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-silgen.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func recvInstantiation(_ i: inout WrappedMagicInt) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIiE) -> () + +public func recvInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIbE) -> () + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: // returnInstantiation() +// CHECK: sil @$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF : $@convention(thin) () -> __CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/using-directive-module-interface.swift b/test/Interop/Cxx/templates/using-directive-module-interface.swift new file mode 100644 index 0000000000000..81b445d21e3d7 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=UsingDirective -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias UsingWrappedMagicNumber = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/using-directive.swift b/test/Interop/Cxx/templates/using-directive.swift new file mode 100644 index 0000000000000..3bae7a8454b33 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import StdlibUnittest +import UsingDirective + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("using-directive") { + let myInt = IntWrapper(value: 333) + var magicInt = UsingWrappedMagicNumber(t: myInt) + expectEqual(magicInt.getValuePlusArg(111), 444) +} + +runAllTests() diff --git a/test/lit.cfg b/test/lit.cfg index e8a4a36443fbf..b35d22fdd150a 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -283,6 +283,7 @@ config.complete_test = inferSwiftBinary('complete-test') config.swift_api_digester = inferSwiftBinary('swift-api-digester') config.swift_refactor = inferSwiftBinary('swift-refactor') config.swift_demangle_yamldump = inferSwiftBinary('swift-demangle-yamldump') +config.swift_demangle = inferSwiftBinary('swift-demangle') config.benchmark_o = inferSwiftBinary('Benchmark_O') config.benchmark_driver = inferSwiftBinary('Benchmark_Driver') config.wasmer = inferSwiftBinary('wasmer') @@ -440,6 +441,7 @@ config.substitutions.append( ('%llvm-readelf', config.llvm_readelf) ) config.substitutions.append( ('%llvm-dis', config.llvm_dis) ) config.substitutions.append( ('%llvm-nm', config.llvm_nm) ) config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_yamldump) ) +config.substitutions.append( ('%swift-demangle', config.swift_demangle) ) config.substitutions.append( ('%Benchmark_O', config.benchmark_o) ) config.substitutions.append( ('%Benchmark_Driver', config.benchmark_driver) ) config.substitutions.append( ('%llvm-strings', config.llvm_strings) ) @@ -2036,4 +2038,3 @@ else: num_extra_inhabitants_64bit = 4096 add_num_extra_inhabitants = "-D#num_extra_inhabitants_64bit={} ".format(num_extra_inhabitants_64bit) config.substitutions.append(('%add_num_extra_inhabitants', add_num_extra_inhabitants)) - From 60e12f109d9f77bce13b2c601e6895939fc6d25f Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 13 Aug 2020 17:46:01 -0400 Subject: [PATCH 157/663] Add a benchmark for protocol conformance testing. --- benchmark/CMakeLists.txt | 1 + .../single-source/ProtocolConformance.swift | 76 +++++++++++++++++++ benchmark/utils/main.swift | 2 + 3 files changed, 79 insertions(+) create mode 100644 benchmark/single-source/ProtocolConformance.swift diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index ef28ed87b2483..1f0f58171f4d7 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -136,6 +136,7 @@ set(SWIFT_BENCH_MODULES single-source/PrefixWhile single-source/Prims single-source/PrimsNonStrongRef + single-source/ProtocolConformance single-source/ProtocolDispatch single-source/ProtocolDispatch2 single-source/Queue diff --git a/benchmark/single-source/ProtocolConformance.swift b/benchmark/single-source/ProtocolConformance.swift new file mode 100644 index 0000000000000..b042065c02ab3 --- /dev/null +++ b/benchmark/single-source/ProtocolConformance.swift @@ -0,0 +1,76 @@ +//===--- ProtocolDispatch.swift -------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let ProtocolConformance = BenchmarkInfo ( + name: "ProtocolConformance", + runFunction: run_ProtocolConformance, + tags: [.validation, .runtime]) + +protocol P {} + +struct One: P {} +struct Two {} + +struct Cat {} + +extension Cat: P where T: P, U: P {} + +protocol Growable {} +extension Growable { + func grow() -> (Growable, Growable) { + return (Cat(), Cat()) + } +} + +extension One: Growable {} +extension Two: Growable {} +extension Cat: Growable {} + +@inline(never) +public func run_ProtocolConformance(_ N: Int) { + var array: [Growable] = [One(), Two()] + var i = 0 + var checks = 0 + + // The expected number of times we expect `elt is P` to be true. + var expectedConforms = 0 + + // The expected number of times we expect `elt is P` to be true + // per iteration, at the current time. + var expectedConformsPerIter = 1 + + // The number of times we've actually seen `elt is P` be true. + var conforms = 0 + while checks < N * 500 { + let (a, b) = array[i].grow() + array.append(a) + array.append(b) + + // The number of times `elt is P` is true per outer iteration + // goes up by 1 when the array's count is a power of 2. + if array.count & (array.count - 1) == 0 { + expectedConformsPerIter += 1 + } + expectedConforms += expectedConformsPerIter + + for elt in array { + if elt is P { + conforms += 1 + } + checks += 1 + } + i += 1 + } + CheckResults(expectedConforms == conforms) +} diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index b4791ad6208e7..aa3504ba35d72 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -131,6 +131,7 @@ import PrefixWhile import Prims import PrimsNonStrongRef import PrimsSplit +import ProtocolConformance import ProtocolDispatch import ProtocolDispatch2 import Queue @@ -317,6 +318,7 @@ registerBenchmark(PrefixWhile) registerBenchmark(Prims) registerBenchmark(PrimsNonStrongRef) registerBenchmark(PrimsSplit) +registerBenchmark(ProtocolConformance) registerBenchmark(ProtocolDispatch) registerBenchmark(ProtocolDispatch2) registerBenchmark(QueueGeneric) From 235be5e5bc16cd9a46f68fdb36a5f5d53e49910e Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 14 Aug 2020 12:49:44 -0700 Subject: [PATCH 158/663] [Concurrency] Factor "is @asyncHandler"? check into a request. This is stating for inference of @asyncHandler. --- include/swift/AST/Decl.h | 5 ++++- include/swift/AST/TypeCheckRequests.h | 18 +++++++++++++++++ include/swift/AST/TypeCheckerTypeIDZone.def | 2 ++ lib/AST/Decl.cpp | 11 +++++++++++ lib/Sema/TypeCheckAttr.cpp | 22 +++++++++++++++++---- 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 5aa4d9c2974d1..5d1061ae9215e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5892,9 +5892,12 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// /// Functions that are an 'async' context can make calls to 'async' functions. bool isAsyncContext() const { - return hasAsync() || getAttrs().hasAttribute(); + return hasAsync() || isAsyncHandler(); } + /// Returns true if the function is an @asyncHandler. + bool isAsyncHandler() const; + /// Returns true if the function body throws. bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; } diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index f067218db105e..2f57ca2c6fd47 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -781,6 +781,24 @@ class SelfAccessKindRequest : void cacheResult(SelfAccessKind value) const; }; +/// Determine whether the given function is an @asyncHandler. +class IsAsyncHandlerRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + bool evaluate(Evaluator &evaluator, FuncDecl *func) const; + +public: + // Caching + bool isCached() const { return true; } +}; + /// Request whether the storage has a mutating getter. class IsGetterMutatingRequest : public SimpleRequest(this); + if (!func) + return false; + + auto mutableFunc = const_cast(func); + return evaluateOrDefault(getASTContext().evaluator, + IsAsyncHandlerRequest{mutableFunc}, + false); +} + BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const { if ((getBodyKind() == BodyKind::Synthesize || getBodyKind() == BodyKind::Unparsed) && diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 0e047c9c3e4d7..33d8ada881a33 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -330,10 +330,8 @@ class AttributeChecker : public AttributeVisitor { return; } - if (checkAsyncHandler(func, /*diagnose=*/true)) { - attr->setInvalid(); - return; - } + // Trigger the request to check for @asyncHandler. + (void)func->isAsyncHandler(); } }; } // end anonymous namespace @@ -5236,3 +5234,19 @@ void swift::addAsyncNotes(FuncDecl *func) { .fixItInsert(func->getAttributeInsertionLoc(false), "@asyncHandler "); } } + +bool IsAsyncHandlerRequest::evaluate( + Evaluator &evaluator, FuncDecl *func) const { + // Check whether the attribute was explicitly specified. + if (auto attr = func->getAttrs().getAttribute()) { + // Check for well-formedness. + if (checkAsyncHandler(func, /*diagnose=*/true)) { + attr->setInvalid(); + return false; + } + + return true; + } + + return false; +} From dabccf6bc2fc9c4bea2a5bce17b97125019c7e6a Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 14 Aug 2020 14:10:44 -0700 Subject: [PATCH 159/663] [Concurrency] Infer @asyncHandler from protocol requirements. Similar to what we do with function builders, infer @asyncHandler from for witnesses to @asyncHandler protocol requirements. --- lib/Sema/TypeCheckAttr.cpp | 54 ++++++++++++++++++++++++++++++++++++ test/attr/asynchandler.swift | 13 +++++++++ 2 files changed, 67 insertions(+) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 33d8ada881a33..7c91ef0c7529b 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -29,6 +29,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/AST/SourceFile.h" #include "swift/AST/StorageImpl.h" #include "swift/AST/TypeCheckRequests.h" @@ -5248,5 +5249,58 @@ bool IsAsyncHandlerRequest::evaluate( return true; } + // Are we in a context where inference is possible? + auto dc = func->getDeclContext(); + if (!dc->isTypeContext() || !dc->getParentSourceFile() || + isa(dc) || !func->hasBody()) + return false; + + // Is it possible to infer @asyncHandler for this function at all? + if (checkAsyncHandler(func, /*diagnose=*/false)) + return false; + + // Add an implicit @asyncHandler attribute and return true. We're done. + auto addImplicitAsyncHandlerAttr = [&] { + func->getAttrs().add(new (func->getASTContext()) AsyncHandlerAttr(true)); + return true; + }; + + // Check whether any of the conformances in the context of the function + // implies @asyncHandler. + { + auto idc = cast(dc->getAsDecl()); + auto conformances = evaluateOrDefault( + dc->getASTContext().evaluator, + LookupAllConformancesInContextRequest{idc}, { }); + + for (auto conformance : conformances) { + auto protocol = conformance->getProtocol(); + for (auto found : protocol->lookupDirect(func->getName())) { + if (!isa(found->getDeclContext())) + continue; + + auto requirement = dyn_cast(found); + if (!requirement) + continue; + + if (!requirement->isAsyncHandler()) + continue; + + auto witness = conformance->getWitnessDecl(requirement); + if (witness != func) + continue; + + return addImplicitAsyncHandlerAttr(); + } + } + } + + // Look through dynamic replacements. + if (auto replaced = func->getDynamicallyReplacedDecl()) { + if (auto replacedFunc = dyn_cast(replaced)) + if (replacedFunc->isAsyncHandler()) + return addImplicitAsyncHandlerAttr(); + } + return false; } diff --git a/test/attr/asynchandler.swift b/test/attr/asynchandler.swift index 82e208206e3f4..e3147f62edbdd 100644 --- a/test/attr/asynchandler.swift +++ b/test/attr/asynchandler.swift @@ -37,3 +37,16 @@ struct X { @asyncHandler init() { } // expected-error@-1{{@asyncHandler may only be used on 'func' declarations}} } + + +// Inference of @asyncHandler +protocol P { + @asyncHandler func callback() +} + +extension X: P { + func callback() { + // okay, it's an async context + let _ = await globalAsyncFunction() + } +} From 85d6f51743edf4fbd7470400ace2a90ee3ed4831 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 14 Aug 2020 14:22:07 -0700 Subject: [PATCH 160/663] build: add additional search paths for Foundation artifacts This allows us to homogenise the foundation build artifacts with swift-tools-support-core, swift-driver, swift-package-manager, swift-numerics, swift-argument-parser. --- utils/build-script-impl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/build-script-impl b/utils/build-script-impl index 7a427b7c43d39..c015efad83dab 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1934,6 +1934,7 @@ for host in "${ALL_HOSTS[@]}"; do DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/Sources/Foundation" DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/Sources/FoundationNetworking" DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/Sources/FoundationXML" + DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/lib" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}/src" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}" @@ -1941,6 +1942,7 @@ for host in "${ALL_HOSTS[@]}"; do DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/Sources/Foundation" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/Sources/FoundationNetworking" DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/Sources/FoundationXML" + DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}/lib" fi # Watchpoint testing is currently disabled: see rdar://38566150. From 77ece2092cc2628f03eb5909c75ab3fbfcc0f2a8 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 14 Aug 2020 14:32:44 -0700 Subject: [PATCH 161/663] [Concurrency] Move concurrency-specific code into its own file. --- lib/Sema/CMakeLists.txt | 1 + lib/Sema/TypeCheckAttr.cpp | 140 -------------------------- lib/Sema/TypeCheckConcurrency.cpp | 160 ++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 140 deletions(-) create mode 100644 lib/Sema/TypeCheckConcurrency.cpp diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index be48c2a9918e4..d35c849fb435f 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -41,6 +41,7 @@ add_swift_host_library(swiftSema STATIC TypeCheckCaptures.cpp TypeCheckCircularity.cpp TypeCheckCodeCompletion.cpp + TypeCheckConcurrency.cpp TypeCheckConstraints.cpp TypeCheckDecl.cpp TypeCheckDeclObjC.cpp diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 7c91ef0c7529b..2187c52e3d15d 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -29,7 +29,6 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" -#include "swift/AST/ProtocolConformance.h" #include "swift/AST/SourceFile.h" #include "swift/AST/StorageImpl.h" #include "swift/AST/TypeCheckRequests.h" @@ -42,66 +41,6 @@ using namespace swift; -/// Check whether the @asyncHandler attribute can be applied to the given -/// function declaration. -/// -/// \param diagnose Whether to emit a diagnostic when a problem is encountered. -/// -/// \returns \c true if there was a problem with adding the attribute, \c false -/// otherwise. -static bool checkAsyncHandler(FuncDecl *func, bool diagnose) { - if (!func->getResultInterfaceType()->isVoid()) { - if (diagnose) { - func->diagnose(diag::asynchandler_returns_value) - .highlight(func->getBodyResultTypeLoc().getSourceRange()); - } - - return true; - } - - if (func->hasThrows()) { - if (diagnose) { - func->diagnose(diag::asynchandler_throws) - .fixItRemove(func->getThrowsLoc()); - } - - return true; - } - - if (func->hasAsync()) { - if (diagnose) { - func->diagnose(diag::asynchandler_async) - .fixItRemove(func->getAsyncLoc()); - } - - return true; - } - - for (auto param : *func->getParameters()) { - if (param->isInOut()) { - if (diagnose) { - param->diagnose(diag::asynchandler_inout_parameter) - .fixItRemove(param->getSpecifierLoc()); - } - - return true; - } - } - - if (func->isMutating()) { - if (diagnose) { - auto diag = func->diagnose(diag::asynchandler_mutating); - if (auto mutatingAttr = func->getAttrs().getAttribute()) { - diag.fixItRemove(mutatingAttr->getRange()); - } - } - - return true; - } - - return false; -} - namespace { /// This emits a diagnostic with a fixit to remove the attribute. template @@ -5225,82 +5164,3 @@ void AttributeChecker::visitTransposeAttr(TransposeAttr *attr) { // Set the resolved linearity parameter indices in the attribute. attr->setParameterIndices(linearParamIndices); } - -void swift::addAsyncNotes(FuncDecl *func) { - func->diagnose(diag::note_add_async_to_function, func->getName()); - - if (!checkAsyncHandler(func, /*diagnose=*/false)) { - func->diagnose( - diag::note_add_asynchandler_to_function, func->getName()) - .fixItInsert(func->getAttributeInsertionLoc(false), "@asyncHandler "); - } -} - -bool IsAsyncHandlerRequest::evaluate( - Evaluator &evaluator, FuncDecl *func) const { - // Check whether the attribute was explicitly specified. - if (auto attr = func->getAttrs().getAttribute()) { - // Check for well-formedness. - if (checkAsyncHandler(func, /*diagnose=*/true)) { - attr->setInvalid(); - return false; - } - - return true; - } - - // Are we in a context where inference is possible? - auto dc = func->getDeclContext(); - if (!dc->isTypeContext() || !dc->getParentSourceFile() || - isa(dc) || !func->hasBody()) - return false; - - // Is it possible to infer @asyncHandler for this function at all? - if (checkAsyncHandler(func, /*diagnose=*/false)) - return false; - - // Add an implicit @asyncHandler attribute and return true. We're done. - auto addImplicitAsyncHandlerAttr = [&] { - func->getAttrs().add(new (func->getASTContext()) AsyncHandlerAttr(true)); - return true; - }; - - // Check whether any of the conformances in the context of the function - // implies @asyncHandler. - { - auto idc = cast(dc->getAsDecl()); - auto conformances = evaluateOrDefault( - dc->getASTContext().evaluator, - LookupAllConformancesInContextRequest{idc}, { }); - - for (auto conformance : conformances) { - auto protocol = conformance->getProtocol(); - for (auto found : protocol->lookupDirect(func->getName())) { - if (!isa(found->getDeclContext())) - continue; - - auto requirement = dyn_cast(found); - if (!requirement) - continue; - - if (!requirement->isAsyncHandler()) - continue; - - auto witness = conformance->getWitnessDecl(requirement); - if (witness != func) - continue; - - return addImplicitAsyncHandlerAttr(); - } - } - } - - // Look through dynamic replacements. - if (auto replaced = func->getDynamicallyReplacedDecl()) { - if (auto replacedFunc = dyn_cast(replaced)) - if (replacedFunc->isAsyncHandler()) - return addImplicitAsyncHandlerAttr(); - } - - return false; -} diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp new file mode 100644 index 0000000000000..153ceb1526d20 --- /dev/null +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -0,0 +1,160 @@ +//===--- TypeCheckConcurrency.cpp - Concurrency ---------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file implements type checking support for Swift's concurrency model. +// +//===----------------------------------------------------------------------===// +#include "TypeChecker.h" +#include "swift/AST/ParameterList.h" +#include "swift/AST/ProtocolConformance.h" +#include "swift/AST/TypeCheckRequests.h" + +using namespace swift; + +/// Check whether the @asyncHandler attribute can be applied to the given +/// function declaration. +/// +/// \param diagnose Whether to emit a diagnostic when a problem is encountered. +/// +/// \returns \c true if there was a problem with adding the attribute, \c false +/// otherwise. +static bool checkAsyncHandler(FuncDecl *func, bool diagnose) { + if (!func->getResultInterfaceType()->isVoid()) { + if (diagnose) { + func->diagnose(diag::asynchandler_returns_value) + .highlight(func->getBodyResultTypeLoc().getSourceRange()); + } + + return true; + } + + if (func->hasThrows()) { + if (diagnose) { + func->diagnose(diag::asynchandler_throws) + .fixItRemove(func->getThrowsLoc()); + } + + return true; + } + + if (func->hasAsync()) { + if (diagnose) { + func->diagnose(diag::asynchandler_async) + .fixItRemove(func->getAsyncLoc()); + } + + return true; + } + + for (auto param : *func->getParameters()) { + if (param->isInOut()) { + if (diagnose) { + param->diagnose(diag::asynchandler_inout_parameter) + .fixItRemove(param->getSpecifierLoc()); + } + + return true; + } + } + + if (func->isMutating()) { + if (diagnose) { + auto diag = func->diagnose(diag::asynchandler_mutating); + if (auto mutatingAttr = func->getAttrs().getAttribute()) { + diag.fixItRemove(mutatingAttr->getRange()); + } + } + + return true; + } + + return false; +} + +void swift::addAsyncNotes(FuncDecl *func) { + func->diagnose(diag::note_add_async_to_function, func->getName()); + + if (!checkAsyncHandler(func, /*diagnose=*/false)) { + func->diagnose( + diag::note_add_asynchandler_to_function, func->getName()) + .fixItInsert(func->getAttributeInsertionLoc(false), "@asyncHandler "); + } +} + +bool IsAsyncHandlerRequest::evaluate( + Evaluator &evaluator, FuncDecl *func) const { + // Check whether the attribute was explicitly specified. + if (auto attr = func->getAttrs().getAttribute()) { + // Check for well-formedness. + if (checkAsyncHandler(func, /*diagnose=*/true)) { + attr->setInvalid(); + return false; + } + + return true; + } + + // Are we in a context where inference is possible? + auto dc = func->getDeclContext(); + if (!dc->isTypeContext() || !dc->getParentSourceFile() || + isa(dc) || !func->hasBody()) + return false; + + // Is it possible to infer @asyncHandler for this function at all? + if (checkAsyncHandler(func, /*diagnose=*/false)) + return false; + + // Add an implicit @asyncHandler attribute and return true. We're done. + auto addImplicitAsyncHandlerAttr = [&] { + func->getAttrs().add(new (func->getASTContext()) AsyncHandlerAttr(true)); + return true; + }; + + // Check whether any of the conformances in the context of the function + // implies @asyncHandler. + { + auto idc = cast(dc->getAsDecl()); + auto conformances = evaluateOrDefault( + dc->getASTContext().evaluator, + LookupAllConformancesInContextRequest{idc}, { }); + + for (auto conformance : conformances) { + auto protocol = conformance->getProtocol(); + for (auto found : protocol->lookupDirect(func->getName())) { + if (!isa(found->getDeclContext())) + continue; + + auto requirement = dyn_cast(found); + if (!requirement) + continue; + + if (!requirement->isAsyncHandler()) + continue; + + auto witness = conformance->getWitnessDecl(requirement); + if (witness != func) + continue; + + return addImplicitAsyncHandlerAttr(); + } + } + } + + // Look through dynamic replacements. + if (auto replaced = func->getDynamicallyReplacedDecl()) { + if (auto replacedFunc = dyn_cast(replaced)) + if (replacedFunc->isAsyncHandler()) + return addImplicitAsyncHandlerAttr(); + } + + return false; +} From f91fe9c0c1d7fa5e0b74d119ea58bb8b929966e8 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Fri, 14 Aug 2020 14:33:28 -0700 Subject: [PATCH 162/663] Use SWIFT_SDK_${prefix}_USE_ISYSROOT to select which SDKs should be building with -isysroot (#33469) --- cmake/modules/AddSwift.cmake | 2 +- cmake/modules/SwiftConfigureSDK.cmake | 5 +++++ stdlib/cmake/modules/AddSwiftStdlib.cmake | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 604870d28b6e3..ec61d2abb836a 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -93,7 +93,7 @@ function(_add_host_variant_c_compile_link_flags name) set(_sysroot "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_PATH}") - if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_APPLE_PLATFORMS) + if(SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_USE_ISYSROOT) target_compile_options(${name} PRIVATE -isysroot;${_sysroot}) elseif(NOT SWIFT_COMPILER_IS_MSVC_LIKE AND NOT "${_sysroot}" STREQUAL "/") target_compile_options(${name} PRIVATE --sysroot=${_sysroot}) diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake index 52c08025e62a0..feb7f513c96ce 100644 --- a/cmake/modules/SwiftConfigureSDK.cmake +++ b/cmake/modules/SwiftConfigureSDK.cmake @@ -145,6 +145,8 @@ endfunction() # SWIFT_SDK_${prefix}_LIB_SUBDIR Library subdir for this SDK # SWIFT_SDK_${prefix}_VERSION_MIN_NAME Version min name for this SDK # SWIFT_SDK_${prefix}_TRIPLE_NAME Triple name for this SDK +# SWIFT_SDK_${prefix}_OBJECT_FORMAT The object file format (e.g. MACHO) +# SWIFT_SDK_${prefix}_USE_ISYSROOT Whether to use -isysroot # SWIFT_SDK_${prefix}_ARCHITECTURES Architectures (as a list) # SWIFT_SDK_${prefix}_IS_SIMULATOR Whether this is a simulator target. # SWIFT_SDK_${prefix}_ARCH_${ARCH}_TRIPLE Triple name @@ -187,6 +189,7 @@ macro(configure_sdk_darwin set(SWIFT_SDK_${prefix}_VERSION_MIN_NAME "${version_min_name}") set(SWIFT_SDK_${prefix}_TRIPLE_NAME "${triple_name}") set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "MACHO") + set(SWIFT_SDK_${prefix}_USE_ISYSROOT TRUE) set(SWIFT_SDK_${prefix}_ARCHITECTURES ${architectures}) if(SWIFT_DARWIN_SUPPORTED_ARCHS) @@ -270,6 +273,7 @@ macro(configure_sdk_unix name architectures) else() set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "ELF") endif() + set(SWIFT_SDK_${prefix}_USE_ISYSROOT FALSE) foreach(arch ${architectures}) if("${prefix}" STREQUAL "ANDROID") @@ -432,6 +436,7 @@ macro(configure_sdk_windows name environment architectures) set(SWIFT_SDK_${prefix}_LIB_SUBDIR "windows") set(SWIFT_SDK_${prefix}_ARCHITECTURES "${architectures}") set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "COFF") + set(SWIFT_SDK_${prefix}_USE_ISYSROOT FALSE) foreach(arch ${architectures}) if(arch STREQUAL armv7) diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 7c973d829fbdb..72dbb31753fe4 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -98,7 +98,7 @@ function(_add_target_variant_c_compile_link_flags) endif() set(_sysroot "${SWIFT_SDK_${CFLAGS_SDK}_ARCH_${CFLAGS_ARCH}_PATH}") - if(IS_DARWIN) + if(SWIFT_SDK_${CFLAGS_SDK}_USE_ISYSROOT) list(APPEND result "-isysroot" "${_sysroot}") elseif(NOT SWIFT_COMPILER_IS_MSVC_LIKE AND NOT "${_sysroot}" STREQUAL "/") list(APPEND result "--sysroot=${_sysroot}") From 5a0f3c43b1a19d85d5a3bd50742bacab9823defd Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 14 Aug 2020 14:50:55 -0700 Subject: [PATCH 163/663] [Concurrency] Don't infer @asyncHandler unless concurrency is enabled. --- lib/Sema/TypeCheckConcurrency.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 153ceb1526d20..f70cc61096e13 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -103,6 +103,9 @@ bool IsAsyncHandlerRequest::evaluate( return true; } + if (!func->getASTContext().LangOpts.EnableExperimentalConcurrency) + return false; + // Are we in a context where inference is possible? auto dc = func->getDeclContext(); if (!dc->isTypeContext() || !dc->getParentSourceFile() || From d9a9b59634ec677a5838de099802637b5887e150 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 14 Aug 2020 15:56:27 -0700 Subject: [PATCH 164/663] [CodeCompletion] Skip an ASTScope assertion for labeled statements Code completion performs 'typeCheckASTNodeAtLoc()' which ignores 'StmtChecker::ActiveLabeledStmts'. Since this is not necessary for code completions, skip an assertion to verify the correctness of ASTScope. rdar://problem/67102611 --- lib/Sema/TypeCheckStmt.cpp | 3 ++- validation-test/IDE/crashers_2_fixed/rdar67102611.swift | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 validation-test/IDE/crashers_2_fixed/rdar67102611.swift diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 9b8af8759bab2..b385eb96e9ec0 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -691,7 +691,8 @@ class StmtChecker : public StmtVisitor { // is equivalent to what we have here. if (LS->getStartLoc().isValid() && sourceFile && SC.getASTContext().LangOpts.EnableASTScopeLookup && - !SC.getASTContext().Diags.hadAnyError()) { + !SC.getASTContext().Diags.hadAnyError() && + !SC.LeaveBraceStmtBodyUnchecked) { // The labeled statements from ASTScope lookup have the // innermost labeled statement first, so reverse it to // match the data structure maintained here. diff --git a/validation-test/IDE/crashers_2_fixed/rdar67102611.swift b/validation-test/IDE/crashers_2_fixed/rdar67102611.swift new file mode 100644 index 0000000000000..c5069e7550cbb --- /dev/null +++ b/validation-test/IDE/crashers_2_fixed/rdar67102611.swift @@ -0,0 +1,6 @@ +// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s > /dev/null + +for x in "foo" { + if x.#^A^# { + } +} From 17926b9c5e1c8bd2fdb65d0821ad88244af68b68 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Fri, 14 Aug 2020 16:47:14 -0700 Subject: [PATCH 165/663] [ConstraintLocator] Statically enforce that all custom path elements inherit from StoredPointerElement or StoredIntegerElement. --- lib/Sema/ConstraintLocator.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index eb402ad00909c..fd5b07a155675 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -780,6 +780,36 @@ class LocatorPathElt::ArgumentAttribute final : public StoredIntegerElement<1> { } }; +namespace details { + template + class PathElement { + static constexpr bool hasStoredValueImpl(...) { return false; } + + template + static constexpr bool hasStoredValueImpl(StoredIntegerElement *) { return true; } + + template + static constexpr bool hasStoredValueImpl(StoredPointerElement *) { return true; } + + public: + static constexpr bool hasStoredValue() { + return hasStoredValueImpl(static_cast(nullptr)); + } + }; +} + +template +constexpr bool isValidCustomPathElement() { + return details::PathElement::hasStoredValue(); +} + +// All custom path element classes must inherit from StoredIntegerElement or StoredPointerElement +#define CUSTOM_LOCATOR_PATH_ELT(Name) \ +static_assert(isValidCustomPathElement(), \ + "Custom path elements must inherit from StoredIntegerElement or StoredPointerElement"); +#include "ConstraintLocatorPathElts.def" + + /// A simple stack-only builder object that constructs a /// constraint locator without allocating memory. /// From 11c9184c6c24dbe0afba36e04328b035bbed00f3 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Fri, 14 Aug 2020 17:05:51 -0700 Subject: [PATCH 166/663] Use SWIFT_SDK_${sdk}_OBJECT_FORMAT to choose whether to use lipo and multi-arch builds --- stdlib/cmake/modules/AddSwiftStdlib.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 72dbb31753fe4..491acd2dfc4ee 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -501,7 +501,7 @@ function(_add_swift_lipo_target) list(APPEND source_binaries $) endforeach() - if(${LIPO_SDK} IN_LIST SWIFT_APPLE_PLATFORMS) + if("${SWIFT_SDK_${LIPO_SDK}_OBJECT_FORMAT}" STREQUAL "MACHO") if(LIPO_CODESIGN) set(codesign_command COMMAND "codesign" "-f" "-s" "-" "${LIPO_OUTPUT}") endif() From aa924196ff202fc2f7e1d820cd59bb4f85173480 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Fri, 14 Aug 2020 17:06:38 -0700 Subject: [PATCH 167/663] Add a flag to build the stdlib without COMPATIBILITY_OVERRIDE (#33438) --- stdlib/CMakeLists.txt | 12 ++++++++++++ stdlib/cmake/modules/AddSwiftStdlib.cmake | 4 ++++ stdlib/public/runtime/CompatibilityOverride.cpp | 4 ++++ stdlib/public/runtime/CompatibilityOverride.h | 11 +++++++++++ stdlib/public/runtime/ImageInspectionMachO.cpp | 4 ++++ utils/build-presets.ini | 1 + utils/build-script-impl | 2 ++ 7 files changed, 38 insertions(+) diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index 00f23b8a0f267..70d45d3821c1d 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -9,6 +9,18 @@ project(swift-stdlib LANGUAGES C CXX) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") +# +# User-configurable options for the standard library. +# + +option(SWIFT_ENABLE_COMPATIBILITY_OVERRIDES + "Support back-deploying compatibility fixes for newer apps running on older runtimes." + TRUE) + +# +# End of user-configurable options. +# + include(AddSwiftStdlib) # Create convenience targets for the Swift standard library. diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 491acd2dfc4ee..a54608d13eff4 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -333,6 +333,10 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-DSWIFT_OBJC_INTEROP=0") endif() + if(NOT SWIFT_ENABLE_COMPATIBILITY_OVERRIDES) + list(APPEND result "-DSWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES") + endif() + set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) endfunction() diff --git a/stdlib/public/runtime/CompatibilityOverride.cpp b/stdlib/public/runtime/CompatibilityOverride.cpp index 9011026cb7035..000ff0dff2600 100644 --- a/stdlib/public/runtime/CompatibilityOverride.cpp +++ b/stdlib/public/runtime/CompatibilityOverride.cpp @@ -14,6 +14,8 @@ // //===----------------------------------------------------------------------===// +#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + #include "CompatibilityOverride.h" #include "ImageInspection.h" @@ -68,3 +70,5 @@ static OverrideSection *getOverrideSectionPtr() { return Section->name; \ } #include "CompatibilityOverride.def" + +#endif // #ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES diff --git a/stdlib/public/runtime/CompatibilityOverride.h b/stdlib/public/runtime/CompatibilityOverride.h index abc2eea227424..9932d3135bd22 100644 --- a/stdlib/public/runtime/CompatibilityOverride.h +++ b/stdlib/public/runtime/CompatibilityOverride.h @@ -24,6 +24,15 @@ namespace swift { +#ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + +#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + attrs ccAttrs ret namespace swift_ ## name typedArgs { \ + return swift_ ## name ## Impl namedArgs; \ + } + +#else // #ifdef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + #define COMPATIBILITY_UNPAREN(...) __VA_ARGS__ #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ @@ -56,6 +65,8 @@ namespace swift { return swift_ ## name ## Impl namedArgs; \ } +#endif // #else SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + } /* end namespace swift */ #endif /* COMPATIBILITY_OVERRIDE_H */ diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp index a34246b794901..643cd66589888 100644 --- a/stdlib/public/runtime/ImageInspectionMachO.cpp +++ b/stdlib/public/runtime/ImageInspectionMachO.cpp @@ -169,6 +169,8 @@ int swift::lookupSymbol(const void *address, SymbolInfo *info) { return 1; } +#ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + void *swift::lookupSection(const char *segment, const char *section, size_t *outSize) { unsigned long size; auto *executableHeader = static_cast(_NSGetMachExecuteHeader()); @@ -178,4 +180,6 @@ void *swift::lookupSection(const char *segment, const char *section, size_t *out return static_cast(data); } +#endif // #ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES + #endif // defined(__APPLE__) && defined(__MACH__) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 98eacd8970755..5854c401167bf 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2390,6 +2390,7 @@ build-swift-dynamic-sdk-overlay=0 build-swift-dynamic-stdlib=0 build-swift-static-stdlib=1 swift-objc-interop=0 +swift-enable-compatibility-overrides=0 [preset: stdlib_S_standalone_minimal_macho_x86_64,build] mixin-preset= diff --git a/utils/build-script-impl b/utils/build-script-impl index 127f6d8c30f32..b9f51aeae1060 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -193,6 +193,7 @@ KNOWN_SETTINGS=( sil-verify-all "0" "If enabled, run the SIL verifier after each transform when building Swift files during this build process" stdlib-deployment-targets "" "space-separated list of targets to configure the Swift standard library to be compiled or cross-compiled for" swift-objc-interop "" "whether to enable interoperability with Objective-C, default is 1 on Apple platfors, 0 otherwise" + swift-enable-compatibility-overrides "1" "whether to support back-deploying compatibility fixes for newer apps running on older runtimes" ## FREESTANDING Stdlib Options swift-freestanding-sdk "" "which SDK to use when building the FREESTANDING stdlib" @@ -1763,6 +1764,7 @@ for host in "${ALL_HOSTS[@]}"; do -DSWIFT_STDLIB_BUILD_TYPE:STRING="${SWIFT_STDLIB_BUILD_TYPE}" -DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}") -DSWIFT_STDLIB_USE_NONATOMIC_RC:BOOL=$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}") + -DSWIFT_ENABLE_COMPATIBILITY_OVERRIDES:BOOL=$(true_false "${SWIFT_ENABLE_COMPATIBILITY_OVERRIDES}") -DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS:BOOL=$(true_false "${SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS}") -DSWIFT_NATIVE_LLVM_TOOLS_PATH:STRING="${native_llvm_tools_path}" -DSWIFT_NATIVE_CLANG_TOOLS_PATH:STRING="${native_clang_tools_path}" From 925835f1581c046e3de86ad4096e5279fbf31e36 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Fri, 14 Aug 2020 21:04:02 -0700 Subject: [PATCH 168/663] NFC: Use SWIFT_APPLE_PLATFORMS and remove is_darwin_based_sdk --- stdlib/cmake/modules/AddSwiftStdlib.cmake | 19 ++----------------- stdlib/cmake/modules/SwiftSource.cmake | 5 ++--- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index a54608d13eff4..7f5ca365da53d 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -2,20 +2,6 @@ include(AddSwift) include(SwiftSource) -function(is_darwin_based_sdk sdk_name out_var) - if ("${sdk_name}" STREQUAL "OSX" OR - "${sdk_name}" STREQUAL "IOS" OR - "${sdk_name}" STREQUAL "IOS_SIMULATOR" OR - "${sdk_name}" STREQUAL "TVOS" OR - "${sdk_name}" STREQUAL "TVOS_SIMULATOR" OR - "${sdk_name}" STREQUAL "WATCHOS" OR - "${sdk_name}" STREQUAL "WATCHOS_SIMULATOR") - set(${out_var} TRUE PARENT_SCOPE) - else() - set(${out_var} FALSE PARENT_SCOPE) - endif() -endfunction() - function(add_dependencies_multiple_targets) cmake_parse_arguments( ADMT # prefix @@ -63,8 +49,7 @@ function(_add_target_variant_c_compile_link_flags) set(result ${${CFLAGS_RESULT_VAR_NAME}}) - is_darwin_based_sdk("${CFLAGS_SDK}" IS_DARWIN) - if(IS_DARWIN) + if("${CFLAGS_SDK}" IN_LIST SWIFT_APPLE_PLATFORMS) # Check if there's a specific OS deployment version needed for this invocation if("${CFLAGS_SDK}" STREQUAL "OSX") if(DEFINED maccatalyst_build_flavor) @@ -113,7 +98,7 @@ function(_add_target_variant_c_compile_link_flags) endif() endif() - if(IS_DARWIN) + if("${CFLAGS_SDK}" IN_LIST SWIFT_APPLE_PLATFORMS) # We collate -F with the framework path to avoid unwanted deduplication # of options by target_compile_options -- this way no undesired # side effects are introduced should a new search path be added. diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index 2fe4ce628afa7..5041c931f06dd 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -210,8 +210,7 @@ function(_add_target_variant_swift_compile_flags list(APPEND result "-sdk" "${SWIFT_SDK_${sdk}_ARCH_${arch}_PATH}") endif() - is_darwin_based_sdk("${sdk}" IS_DARWIN) - if(IS_DARWIN) + if("${sdk}" IN_LIST SWIFT_APPLE_PLATFORMS) set(sdk_deployment_version "${SWIFT_SDK_${sdk}_DEPLOYMENT_VERSION}") get_target_triple(target target_variant "${sdk}" "${arch}" MACCATALYST_BUILD_FLAVOR "${VARIANT_MACCATALYST_BUILD_FLAVOR}" @@ -237,7 +236,7 @@ function(_add_target_variant_swift_compile_flags list(APPEND result "-resource-dir" "${SWIFTLIB_DIR}") endif() - if(IS_DARWIN) + if("${sdk}" IN_LIST SWIFT_APPLE_PLATFORMS) # We collate -F with the framework path to avoid unwanted deduplication # of options by target_compile_options -- this way no undesired # side effects are introduced should a new search path be added. From 99e518bb8597fbd7df4de7220878e88a6345c673 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 14 Aug 2020 21:20:34 -0700 Subject: [PATCH 169/663] Guard Obj-C specifics in Metadata.cpp with SWIFT_OBJC_INTEROP --- stdlib/public/runtime/Metadata.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 6d27888429c13..1dfe45dd8c62f 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -49,6 +49,8 @@ #endif #if SWIFT_PTRAUTH #include +#endif +#if SWIFT_OBJC_INTEROP extern "C" void _objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler) (Class _Nonnull oldClass, Class _Nonnull newClass)); #endif @@ -395,7 +397,7 @@ static GenericMetadataCache &unsafeGetInitializedCache( return lazyCache->unsafeGetAlreadyInitialized(); } -#if SWIFT_PTRAUTH +#if SWIFT_PTRAUTH && SWIFT_OBJC_INTEROP static void swift_objc_classCopyFixupHandler(Class oldClass, Class newClass) { auto oldClassMetadata = reinterpret_cast(oldClass); From 6d84c18ba4cbc2630376e615436d0996a92105ae Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 14 Aug 2020 19:11:19 -0400 Subject: [PATCH 170/663] Sema: Check 'where' clause requirements on type witnesses In the included test case, conformance checking of Wrapper : B would pick up typealias Foo as a witness for the associated type B.Foo. However, this typealias Foo is defined in a constrained extension where T : A, and the underlying type references the associated type A.Foo on T. The resulting substitution is invalid when the conformance Wrapper : B is used in a context where T does not conform to A. Instead, we should ignore this typealias entirely, since it appears in an unusable constrained extension. Fixes , , . --- lib/Sema/TypeCheckProtocol.cpp | 26 ++++++- lib/Sema/TypeCheckType.cpp | 64 +++++++++------- lib/Sema/TypeChecker.h | 5 ++ .../conditionally_defined_types.swift | 38 +++++----- test/Constraints/rdar39931339.swift | 4 +- ...uirement_failures_in_contextual_type.swift | 6 +- .../Generics/constrained_type_witnesses.swift | 75 +++++++++++++++++++ ...re_clause_contextually_generic_decls.swift | 4 +- .../protocol/req/missing_conformance.swift | 1 + test/decl/var/property_wrappers.swift | 2 +- .../compiler_crashers_2_fixed/sr12327.swift | 42 +++++++++++ .../compiler_crashers_2_fixed/sr9199.swift | 4 +- 12 files changed, 212 insertions(+), 59 deletions(-) create mode 100644 test/Generics/constrained_type_witnesses.swift create mode 100644 validation-test/compiler_crashers_2_fixed/sr12327.swift diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index e68a7b2d095fa..8de95a8d88c57 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3877,10 +3877,32 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( SmallVector, 2> nonViable; for (auto candidate : candidates) { // Skip nested generic types. - if (auto *genericDecl = dyn_cast(candidate.Member)) + if (auto *genericDecl = dyn_cast(candidate.Member)) { + // If the declaration has generic parameters, it cannot witness an + // associated type. if (genericDecl->isGeneric()) continue; + // As a narrow fix for a source compatibility issue with SwiftUI's + // swiftinterface, allow the conformance if the underlying type of + // the typealias is Never. + // + // FIXME: This should be conditionalized on a new language version. + bool skipRequirementCheck = false; + if (auto *typeAliasDecl = dyn_cast(candidate.Member)) { + if (typeAliasDecl->getUnderlyingType()->isUninhabited()) + skipRequirementCheck = true; + } + + // If the type comes from a constrained extension or has a 'where' + // clause, check those requirements now. + if (!skipRequirementCheck && + !TypeChecker::checkContextualRequirements(genericDecl, Adoptee, + SourceLoc(), DC)) { + continue; + } + } + // Skip typealiases with an unbound generic type as their underlying type. if (auto *typeAliasDecl = dyn_cast(candidate.Member)) if (typeAliasDecl->getDeclaredInterfaceType()->is()) @@ -3908,8 +3930,6 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( // If there is a single viable candidate, form a substitution for it. if (viable.size() == 1) { auto interfaceType = viable.front().MemberType; - if (interfaceType->hasArchetype()) - interfaceType = interfaceType->mapTypeOutOfContext(); recordTypeWitness(assocType, interfaceType, viable.front().Member); return ResolveWitnessResult::Success; } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index c28005a603b29..aacf189a1558a 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -597,26 +597,18 @@ static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) { return BGT->getGenericArgs().front()->isVoid(); } -static Type checkContextualRequirements(Type type, - SourceLoc loc, - DeclContext *dc) { - // Even if the type is not generic, it might be inside of a generic - // context, so we need to check requirements. - GenericTypeDecl *decl; - Type parentTy; - if (auto *aliasTy = dyn_cast(type.getPointer())) { - decl = aliasTy->getDecl(); - parentTy = aliasTy->getParent(); - } else if (auto *nominalTy = type->getAs()) { - decl = nominalTy->getDecl(); - parentTy = nominalTy->getParent(); - } else { - return type; - } - +/// Even if the type is not generic, it might be inside of a generic +/// context or have a free-standing 'where' clause, so we need to +/// those check requirements too. +/// +/// Return true on success. +bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl, + Type parentTy, + SourceLoc loc, + DeclContext *dc) { if (!parentTy || parentTy->hasUnboundGenericType() || parentTy->hasTypeVariable()) { - return type; + return true; } auto &ctx = dc->getASTContext(); @@ -631,7 +623,7 @@ static Type checkContextualRequirements(Type type, else if (ext && ext->isConstrainedExtension()) noteLoc = ext->getLoc(); else - return type; + return true; if (noteLoc.isInvalid()) noteLoc = loc; @@ -640,15 +632,18 @@ static Type checkContextualRequirements(Type type, const auto subMap = parentTy->getContextSubstitutions(decl->getDeclContext()); const auto genericSig = decl->getGenericSignature(); if (!genericSig) { - ctx.Diags.diagnose(loc, diag::recursive_decl_reference, - decl->getDescriptiveKind(), decl->getName()); - decl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); - return ErrorType::get(ctx); + if (loc.isValid()) { + ctx.Diags.diagnose(loc, diag::recursive_decl_reference, + decl->getDescriptiveKind(), decl->getName()); + decl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); + } + return false; } const auto result = TypeChecker::checkGenericArguments( - dc, loc, noteLoc, type, + dc, loc, noteLoc, + decl->getDeclaredInterfaceType(), genericSig->getGenericParams(), genericSig->getRequirements(), QueryTypeSubstitutionMap{subMap}); @@ -656,9 +651,9 @@ static Type checkContextualRequirements(Type type, switch (result) { case RequirementCheckResult::Failure: case RequirementCheckResult::SubstitutionFailure: - return ErrorType::get(ctx); + return false; case RequirementCheckResult::Success: - return type; + return true; } llvm_unreachable("invalid requirement check type"); } @@ -709,7 +704,22 @@ static Type applyGenericArguments(Type type, TypeResolution resolution, if (resolution.getStage() == TypeResolutionStage::Structural) return type; - return checkContextualRequirements(type, loc, dc); + GenericTypeDecl *decl; + Type parentTy; + if (auto *aliasTy = dyn_cast(type.getPointer())) { + decl = aliasTy->getDecl(); + parentTy = aliasTy->getParent(); + } else if (auto *nominalTy = type->getAs()) { + decl = nominalTy->getDecl(); + parentTy = nominalTy->getParent(); + } else { + return type; + } + + if (TypeChecker::checkContextualRequirements(decl, parentTy, loc, dc)) + return type; + + return ErrorType::get(resolution.getASTContext()); } if (type->hasError()) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index e053cd664fdfc..9ad183c60bc67 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -601,6 +601,11 @@ RequirementCheckResult checkGenericArguments( ArrayRef requirements, TypeSubstitutionFn substitutions, SubstOptions options = None); +bool checkContextualRequirements(GenericTypeDecl *decl, + Type parentTy, + SourceLoc loc, + DeclContext *dc); + /// Add any implicitly-defined constructors required for the given /// struct or class. void addImplicitConstructors(NominalTypeDecl *typeDecl); diff --git a/test/Constraints/conditionally_defined_types.swift b/test/Constraints/conditionally_defined_types.swift index 193d40a7f766d..73ebce7633514 100644 --- a/test/Constraints/conditionally_defined_types.swift +++ b/test/Constraints/conditionally_defined_types.swift @@ -36,12 +36,12 @@ let _ = SameType.Decl3.self let _ = SameType.Decl4.self let _ = SameType.Decl5.self -let _ = SameType.TypeAlias1.self // expected-error {{'SameType.TypeAlias1' (aka 'X') requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.TypeAlias2.self // expected-error {{'SameType.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.TypeAlias1.self // expected-error {{'SameType.TypeAlias1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.TypeAlias2.self // expected-error {{'SameType.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} let _ = SameType.TypeAlias3.self // expected-error {{'SameType.TypeAlias3' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl2.self // expected-error {{'SameType.Decl2' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl3.self // expected-error {{'SameType.Decl3' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl2.self // expected-error {{'SameType.Decl2' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl3.self // expected-error {{'SameType.Decl3' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.self // expected-error {{'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl5.self // expected-error {{'SameType.Decl5' requires the types 'Y' and 'X' be equivalent}} @@ -49,7 +49,7 @@ extension SameType: AssociatedType where T == X {} // expected-note@-1 {{requirement specified as 'T' == 'X' [with T = Y]}} let _ = SameType.T.self -let _ = SameType.T.self // expected-error {{'SameType.T' (aka 'X') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.T.self // expected-error {{'SameType.T' (aka 'X') requires the types 'Y' and 'X' be equivalent}} struct Conforms {} @@ -112,14 +112,14 @@ let _ = SameType.Decl1.Decl3.self let _ = SameType.Decl1.Decl4.self let _ = SameType.Decl1.Decl5.self -let _ = SameType.Decl1.TypeAlias1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.TypeAlias2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.TypeAlias3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl4.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl5.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl4.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl5.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} extension SameType.Decl4 where U == X { // expected-note 5 {{requirement specified as 'U' == 'X' [with U = Y]}} typealias TypeAlias1 = T @@ -144,12 +144,12 @@ let _ = SameType.Decl4.Decl3.self let _ = SameType.Decl4.Decl4.self let _ = SameType.Decl4.Decl5.self -let _ = SameType.Decl4.TypeAlias1.self // expected-error {{'SameType.Decl4.TypeAlias1' (aka 'X') requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.TypeAlias2.self // expected-error {{'SameType.Decl4.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.TypeAlias1.self // expected-error {{'SameType.Decl4.TypeAlias1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.TypeAlias2.self // expected-error {{'SameType.Decl4.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.TypeAlias3.self // expected-error {{'SameType.Decl4.TypeAlias3' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl1.self // expected-error {{'SameType.Decl4.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl2.self // expected-error {{'SameType.Decl4.Decl2' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl3.self // expected-error {{'SameType.Decl4.Decl3' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl1.self // expected-error {{'SameType.Decl4.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl2.self // expected-error {{'SameType.Decl4.Decl2' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl3.self // expected-error {{'SameType.Decl4.Decl3' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.Decl4.self // expected-error {{'SameType.Decl4.Decl4' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.Decl5.self // expected-error {{'SameType.Decl4.Decl5' requires the types 'Y' and 'X' be equivalent}} diff --git a/test/Constraints/rdar39931339.swift b/test/Constraints/rdar39931339.swift index 40add2eb11c18..eee8de950baad 100644 --- a/test/Constraints/rdar39931339.swift +++ b/test/Constraints/rdar39931339.swift @@ -32,12 +32,12 @@ _ = B.S1() // Ok _ = B.S2() // Ok _ = B.S1() // expected-error {{type 'Float' does not conform to protocol 'P'}} _ = B.S2() -// expected-error@-1 {{'B.S2' (aka 'Int') requires the types '[String]' and '[Int]' be equivalent}} +// expected-error@-1 {{'A.S2' (aka 'Int') requires the types '[String]' and '[Int]' be equivalent}} _ = S.A() // Ok _ = S.A() // expected-error {{type 'Int' does not conform to protocol 'P'}} _ = S.B() // expected-error {{type 'String' does not conform to protocol 'P'}} -_ = S.C() // expected-error {{'S.C' (aka 'Int') requires the types 'Int' and 'Float' be equivalent}} +_ = S.C() // expected-error {{'S.C' (aka 'Int') requires the types 'Int' and 'Float' be equivalent}} func foo(_ s: S.Type) { _ = s.A() // expected-error {{referencing type alias 'A' on 'S' requires that 'T' conform to 'P'}} diff --git a/test/Constraints/requirement_failures_in_contextual_type.swift b/test/Constraints/requirement_failures_in_contextual_type.swift index 31eb477fa7153..75bf679ad92ce 100644 --- a/test/Constraints/requirement_failures_in_contextual_type.swift +++ b/test/Constraints/requirement_failures_in_contextual_type.swift @@ -14,11 +14,11 @@ extension A where T == Int32 { // expected-note 3{{requirement specified as 'T' } let _: A.B = 0 -// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} let _: A.C = 0 -// expected-error@-1 {{'A.C' (aka 'Int') requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.C' (aka 'Int') requires the types 'Int' and 'Int32' be equivalent}} let _: A.B.E = 0 -// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} protocol P {} diff --git a/test/Generics/constrained_type_witnesses.swift b/test/Generics/constrained_type_witnesses.swift new file mode 100644 index 0000000000000..e56586e752a64 --- /dev/null +++ b/test/Generics/constrained_type_witnesses.swift @@ -0,0 +1,75 @@ +// RUN: %target-typecheck-verify-swift + +protocol P { + associatedtype A + // expected-note@-1 3{{protocol requires nested type 'A'; do you want to add it?}} +} + +struct S1 {} + +extension S1 where T : P { + typealias A = Int +} + +// This is rejected because S1.A is not a suitable witness for P.A. +extension S1 : P {} +// expected-error@-1 {{type 'S1' does not conform to protocol 'P'}} + +struct S2 {} + +extension S2 where T : P { + typealias A = Never +} + +// Hack: This is OK to make SwiftUI work, which accidentally relies on the +// incorrect behavior with a typealias whose underlying type is 'Never' +// (so it didn't hit the compiler crash). +extension S2 : P {} + +// Here we have a suitable witness +struct S3 {} + +extension S3 where T == Int { + typealias A = Int +} + +extension S3 : P where T == Int {} + +// Check where clause on the type itself + +struct S4 { + typealias A = Int where T : P +} + +extension S4 : P {} +// expected-error@-1 {{type 'S4' does not conform to protocol 'P'}} + +struct S5 { + typealias A = Never where T : P +} + +extension S5 : P {} + +struct S6 { + typealias A = Int where T == Int +} + +extension S6 : P where T == Int {} + +// Witness in a constrained protocol extension +protocol Q { + associatedtype B +} + +extension Q where B == Int { + typealias A = Int +} + +struct S7 : Q, P { + typealias B = Int +} + +struct S8 : Q, P { +// expected-error@-1 {{type 'S8' does not conform to protocol 'P'}} + typealias B = String +} diff --git a/test/Generics/where_clause_contextually_generic_decls.swift b/test/Generics/where_clause_contextually_generic_decls.swift index 96b2c4fb6ed99..27819a167a03f 100644 --- a/test/Generics/where_clause_contextually_generic_decls.swift +++ b/test/Generics/where_clause_contextually_generic_decls.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -typecheck %s -verify -swift-version 4 +// RUN: %target-typecheck-verify-swift -swift-version 4 func bet() where A : B {} // expected-error {{'where' clause cannot be applied to a non-generic top-level declaration}} @@ -148,7 +148,7 @@ _ = Container.NestedAlias2.self // expected-error {{type 'String' does n _ = Container>.NestedClass.self // expected-error {{type 'Container' does not conform to protocol 'Equatable'}} _ = Container.NestedStruct.self // expected-error {{type 'Void' does not conform to protocol 'Sequence'}} _ = Container>.NestedStruct2.self // expected-error {{type 'Void' does not conform to protocol 'Comparable'}} -_ = Container.NestedStruct2.NestedEnum.self // expected-error {{'Container.NestedStruct2.NestedEnum' requires the types 'String.Element' (aka 'Character') and 'Double' be equivalent}} +_ = Container.NestedStruct2.NestedEnum.self // expected-error {{'Container.NestedStruct2.NestedEnum' requires the types 'String.Element' (aka 'Character') and 'Double' be equivalent}} _ = Container.NestedAlias2.self _ = Container.NestedClass.self _ = Container.NestedStruct.self diff --git a/test/decl/protocol/req/missing_conformance.swift b/test/decl/protocol/req/missing_conformance.swift index c838d20cd8557..871c4344c30ef 100644 --- a/test/decl/protocol/req/missing_conformance.swift +++ b/test/decl/protocol/req/missing_conformance.swift @@ -132,6 +132,7 @@ extension CountSteps1 // expected-error {{type 'CountSteps1' does not conform where T : Equatable { typealias Index = Int + // expected-error@-1 {{invalid redeclaration of synthesized implementation for protocol requirement 'Index'}} func index(_ i: Index, offsetBy d: Int) -> Index { return i + d } diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index 736a32a261fa3..b816762cd2cc5 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -1732,7 +1732,7 @@ extension SR_11288_P4 where Self: AnyObject { // expected-note {{requirement spe } struct SR_11288_S4: SR_11288_P4 { - @SR_11288_Wrapper4 var answer = 42 // expected-error {{'SR_11288_S4.SR_11288_Wrapper4' (aka 'SR_11288_S0') requires that 'SR_11288_S4' be a class type}} + @SR_11288_Wrapper4 var answer = 42 // expected-error {{'Self.SR_11288_Wrapper4' (aka 'SR_11288_S0') requires that 'SR_11288_S4' be a class type}} } class SR_11288_C0: SR_11288_P4 { diff --git a/validation-test/compiler_crashers_2_fixed/sr12327.swift b/validation-test/compiler_crashers_2_fixed/sr12327.swift new file mode 100644 index 0000000000000..33a5140a92d27 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr12327.swift @@ -0,0 +1,42 @@ +// RUN: %target-swift-frontend -emit-ir -O %s + +protocol A { + associatedtype Foo // Does not crash if renamed +} + +protocol B { + associatedtype Foo // Does not crash if renamed + var aFoo: Foo { get } +} + +public struct Wrapper { + let wrapped: T +} + +// Removing this extension or combining it with the next one prevents the crash +extension Wrapper: A where T: A { + typealias Foo = Wrapper +} + +extension Wrapper: B where T: B { + var aFoo: Wrapper { + return .init(wrapped: wrapped.aFoo) + } +} + +public struct Model: B { + public struct Foo {} + + public var aFoo: Foo { + return Foo() + } +} + +// Attempting to specialize this method for Wrapper crashes the compiler +func fooString(body: Body) -> String { + return "\(body.aFoo)" +} + +public func foo(_ command: Wrapper) -> String { + return fooString(body: command) +} diff --git a/validation-test/compiler_crashers_2_fixed/sr9199.swift b/validation-test/compiler_crashers_2_fixed/sr9199.swift index 422f46b5579ba..609bb9e4ad46c 100644 --- a/validation-test/compiler_crashers_2_fixed/sr9199.swift +++ b/validation-test/compiler_crashers_2_fixed/sr9199.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -o %t.ll %s +// RUN: not %target-swift-frontend -emit-ir %s // Just make sure we don't crash. @@ -54,4 +54,4 @@ extension Controller: WithReturnType { let controller = Controller() -controller.returnTheThing() \ No newline at end of file +controller.returnTheThing() From 5f26fa84bc7e9979788dd3e9bb580bd8c81a4a19 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 15 Aug 2020 01:15:21 -0400 Subject: [PATCH 171/663] AST: A class-constrained OpenedArchetypeType should have a layout constraint This is now the case for archetypes instantiated from a generic signature; let's establish this invariant for opened types as well. --- lib/AST/ASTContext.cpp | 5 +++ lib/AST/Type.cpp | 3 +- test/SILOptimizer/inline_generics.sil | 49 --------------------------- 3 files changed, 6 insertions(+), 51 deletions(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ca7f74f5f9248..10b81d3183be1 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3835,6 +3835,11 @@ CanOpenedArchetypeType OpenedArchetypeType::get(Type existential, protos.push_back(proto->getDecl()); auto layoutConstraint = layout.getLayoutConstraint(); + if (!layoutConstraint && layout.requiresClass()) { + layoutConstraint = LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Class); + } + auto layoutSuperclass = layout.getSuperclass(); auto arena = AllocationArena::Permanent; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 62142eb9ccb27..1bb6007d38e2f 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4952,8 +4952,7 @@ ReferenceCounting TypeBase::getReferenceCounting() { auto archetype = cast(type); auto layout = archetype->getLayoutConstraint(); (void)layout; - assert(archetype->requiresClass() || - (layout && layout->isRefCounted())); + assert(layout && layout->isRefCounted()); if (auto supertype = archetype->getSuperclass()) return supertype->getReferenceCounting(); return ReferenceCounting::Unknown; diff --git a/test/SILOptimizer/inline_generics.sil b/test/SILOptimizer/inline_generics.sil index 5ba0af36fdfbb..2ca1b70b7b188 100644 --- a/test/SILOptimizer/inline_generics.sil +++ b/test/SILOptimizer/inline_generics.sil @@ -47,55 +47,6 @@ bb0(%0 : $*T, %1 : $*T): return %9 : $() } // end sil function 'testInliningOfGenerics' -sil hidden @P_combine : $@convention(method) (@in T, @guaranteed Self) -> @owned @callee_owned (@in T) -> Bool { -bb0(%0 : $*T, %1 : $Self): - // function_ref P.(combine (first : A1) -> (A1) -> Bool).(closure #1) - %4 = function_ref @_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb : $@convention(thin) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0) -> Bool - %5 = partial_apply %4() : $@convention(thin) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0) -> Bool - destroy_addr %0 : $*T - return %5 : $@callee_owned (@in T) -> Bool -} // end sil function 'P_combine' - -// P.(combine (first : A1) -> (A1) -> Bool).(closure #1) -sil shared @_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb : $@convention(thin) (@in T) -> Bool { -bb0(%0 : $*T): - %2 = integer_literal $Builtin.Int1, -1 - %3 = struct $Bool (%2 : $Builtin.Int1) - destroy_addr %0 : $*T - return %3 : $Bool -} // end sil function '_TFFE50generic_inlining_partial_apply_opened_existentialsPS_1P7combineurFT5firstqd___Fqd__SbU_Fqd__Sb' - - -// Check that P_combine is not inlined into the generic function, because -// doing so would result in a partial_apply instruction, with an opened existential -// in the substitution list. And this cannot be handled by the IRGen yet. -// CHECK-LABEL: sil @dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list -// CHECK: [[FUN_REF:%[0-9]+]] = function_ref @P_combine -// CHECK: apply [[FUN_REF]] -// CHECK: end sil function 'dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list' -sil @dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list : $@convention(thin) (@owned P) -> @owned @callee_owned (@owned T) -> Bool { -bb0(%0 : $P): - %2 = open_existential_ref %0 : $P to $@opened("41B148C8-F49C-11E6-BE69-A45E60E99281") P - // function_ref P.combine (first : A1) -> (A1) -> Bool - %3 = function_ref @P_combine : $@convention(method) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0, @guaranteed τ_0_0) -> @owned @callee_owned (@in τ_1_0) -> Bool - %4 = open_existential_ref %0 : $P to $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P - %5 = witness_method $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P, #P.getSelf : (Self) -> () -> Self, %4 : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0 - %6 = apply %5<@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P>(%4) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0 - %7 = init_existential_ref %6 : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P : $@opened("41B14A4E-F49C-11E6-BE69-A45E60E99281") P, $P - %8 = alloc_stack $P - store %7 to %8 : $*P - %10 = apply %3<@opened("41B148C8-F49C-11E6-BE69-A45E60E99281") P, P>(%8, %2) : $@convention(method) <τ_0_0 where τ_0_0 : P><τ_1_0> (@in τ_1_0, @guaranteed τ_0_0) -> @owned @callee_owned (@in τ_1_0) -> Bool - // function_ref thunk - %11 = function_ref @thunk1 : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool - %12 = partial_apply %11(%10) : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool - // function_ref thunk - %13 = function_ref @thunk2 : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0, @owned @callee_owned (@owned P) -> Bool) -> Bool - %14 = partial_apply %13(%12) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0, @owned @callee_owned (@owned P) -> Bool) -> Bool - dealloc_stack %8 : $*P - strong_release %0 : $P - return %14 : $@callee_owned (@owned T) -> Bool -} // end sil function 'dont_inline_callee_with_opened_existential_in_partial_apply_substitution_list' - // thunk sil shared [transparent] [reabstraction_thunk] @thunk1 : $@convention(thin) (@owned P, @owned @callee_owned (@in P) -> Bool) -> Bool { bb0(%0 : $P, %1 : $@callee_owned (@in P) -> Bool): From a6fbc59b6fe94861035208f1476b78bcd6f97454 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 14 Aug 2020 23:26:20 -0400 Subject: [PATCH 172/663] AST: Simplify ArchetypeType::requiresClass() --- lib/AST/Type.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 1bb6007d38e2f..f26c9e39182af 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3206,14 +3206,8 @@ PrimaryArchetypeType::getNew(const ASTContext &Ctx, } bool ArchetypeType::requiresClass() const { - if (Bits.ArchetypeType.HasSuperclass) - return true; if (auto layout = getLayoutConstraint()) - if (layout->isClass()) - return true; - for (ProtocolDecl *conformed : getConformsTo()) - if (conformed->requiresClass()) - return true; + return layout->isClass(); return false; } From 253c0ac69213321ee674c0438b8f99a8defc2dc7 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 15 Aug 2020 02:40:41 -0400 Subject: [PATCH 173/663] SIL: Generalize some explicit requiresClass() checks to use layout constraints --- lib/SIL/IR/TypeLowering.cpp | 4 ---- lib/SILOptimizer/Transforms/CSE.cpp | 3 --- .../Utils/PerformanceInlinerUtils.cpp | 22 ++++++++++++------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 06587a67372ea..e1d4417e42dd6 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -421,10 +421,6 @@ namespace { RetTy visitArchetypeType(CanArchetypeType type, AbstractionPattern origType) { - if (type->requiresClass()) { - return asImpl().handleReference(type); - } - auto LayoutInfo = type->getLayoutConstraint(); if (LayoutInfo) { if (LayoutInfo->isFixedSizeTrivial()) { diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp index af2cef2882e4a..f62fa49cb3719 100644 --- a/lib/SILOptimizer/Transforms/CSE.cpp +++ b/lib/SILOptimizer/Transforms/CSE.cpp @@ -428,9 +428,6 @@ bool llvm::DenseMapInfo::isEqual(SimpleValue LHS, return false; // ... and other constraints are equal. - if (LHSArchetypeTy->requiresClass() != RHSArchetypeTy->requiresClass()) - return false; - if (LHSArchetypeTy->getSuperclass().getPointer() != RHSArchetypeTy->getSuperclass().getPointer()) return false; diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp index 21f4bc6f5a24c..f8bcce57b36d7 100644 --- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp +++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp @@ -622,14 +622,20 @@ static bool isCallerAndCalleeLayoutConstraintsCompatible(FullApplySite AI) { // The generic parameter has a layout constraint. // Check that the substitution has the same constraint. auto AIReplacement = Type(Param).subst(AISubs); - auto AIArchetype = AIReplacement->getAs(); - if (!AIArchetype) - return false; - auto AILayout = AIArchetype->getLayoutConstraint(); - if (!AILayout) - return false; - if (AILayout != Layout) - return false; + + if (Layout->isClass()) { + if (!AIReplacement->satisfiesClassConstraint()) + return false; + } else { + auto AIArchetype = AIReplacement->getAs(); + if (!AIArchetype) + return false; + auto AILayout = AIArchetype->getLayoutConstraint(); + if (!AILayout) + return false; + if (AILayout != Layout) + return false; + } } return true; } From 61104cf9c66c24573f299b089552be5a2417c335 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 15 Aug 2020 03:05:45 -0400 Subject: [PATCH 174/663] SIL: Clean up AbstractionPattern::getLayoutConstraint() --- lib/SIL/IR/AbstractionPattern.cpp | 32 ++++++++++++------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/lib/SIL/IR/AbstractionPattern.cpp b/lib/SIL/IR/AbstractionPattern.cpp index 98b35f470a549..5592dd1d3bef4 100644 --- a/lib/SIL/IR/AbstractionPattern.cpp +++ b/lib/SIL/IR/AbstractionPattern.cpp @@ -236,7 +236,7 @@ bool AbstractionPattern::requiresClass() const { // ObjC generics are always class constrained. return true; } - + assert(GenericSig && "Dependent type in pattern without generic signature?"); return GenericSig->requiresClass(type); @@ -250,30 +250,23 @@ bool AbstractionPattern::requiresClass() const { } LayoutConstraint AbstractionPattern::getLayoutConstraint() const { - // TODO: `ArchetypeType::getLayoutConstraint` and - // `GenericSignature::getLayoutConstraint` don't always propagate implied - // layout constraints from protocol/class constraints. `requiresClass` - // is, for the time being, the only one we really care about, though, and - // it behaves correctly. - if (requiresClass()) { - return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class); - } - return LayoutConstraint(); - -#if GET_LAYOUT_CONSTRAINT_WORKED_THE_WAY_I_WANT switch (getKind()) { case Kind::Opaque: return LayoutConstraint(); case Kind::Type: - case Kind::Discard: { + case Kind::Discard: + case Kind::ClangType: { auto type = getType(); if (auto archetype = dyn_cast(type)) { - auto archetypeSig = archetype->getGenericEnvironment() - ->getGenericSignature(); - return archetypeSig->getLayoutConstraint(archetype->getInterfaceType()); - } - else if (isa(type) || - isa(type)) { + return archetype->getLayoutConstraint(); + } else if (isa(type) || + isa(type)) { + if (getKind() == Kind::ClangType) { + // ObjC generics are always class constrained. + return LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Class); + } + assert(GenericSig && "Dependent type in pattern without generic signature?"); return GenericSig->getLayoutConstraint(type); @@ -283,7 +276,6 @@ LayoutConstraint AbstractionPattern::getLayoutConstraint() const { default: return LayoutConstraint(); } -#endif } bool AbstractionPattern::matchesTuple(CanTupleType substType) { From 0c0a96339f293a0b9d53d2b5ca08496d6a2730fd Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 14 Aug 2020 19:08:26 -0400 Subject: [PATCH 175/663] SIL: Print ErrorTypes with @error_type prefix to avoid confusion In diagnostics, we print wrapped ErrorTypes as their original type. This is confusing when debugging SIL issues though, where we don't expect to see ErrorTypes. Print them as '@error_type ' instead. --- lib/AST/ASTPrinter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 72fabc46d94a5..2d50c54be3f3d 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3780,8 +3780,11 @@ class TypePrinter : public TypeVisitor { } void visitErrorType(ErrorType *T) { - if (auto originalType = T->getOriginalType()) + if (auto originalType = T->getOriginalType()) { + if (Options.PrintInSILBody) + Printer << "@error_type "; visit(originalType); + } else Printer << "<>"; } From 2a199e8bf75afcd604f9d7b13ab19ee382215774 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 14 Aug 2020 23:29:07 -0400 Subject: [PATCH 176/663] IRGen: Simplify TypeConverter::convertArchetypeType() --- lib/IRGen/GenArchetype.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp index 84f9c98b2e55e..c81255520af49 100644 --- a/lib/IRGen/GenArchetype.cpp +++ b/lib/IRGen/GenArchetype.cpp @@ -284,8 +284,7 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) { // If the archetype is class-constrained, use a class pointer // representation. - if (archetype->requiresClass() || - (layout && layout->isRefCounted())) { + if (layout && layout->isRefCounted()) { auto refcount = archetype->getReferenceCounting(); llvm::PointerType *reprTy; From e23cc5414520488ddfe480e2a3b6d7ad364da79e Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Sat, 15 Aug 2020 09:39:15 -0700 Subject: [PATCH 177/663] [IRGen] Skip reemitting fields referenced by type context descriptor. When reemitting a type context descriptor, several fields - method lookup function - dispatch thunk - nonoverride method descriptor were previously being reemitted. In a couple of earlier commits, that behavior was altered to delete the fields before reemitting them. 3ad2777a68d [IRGen] Erase nonoverride descriptor on emission. c25c180c088 [IRGen] Erase thunks before emission. Here, the behavior is changed to simply exit early when these fields are being reemitted. Also an assertion is added that these fields are redefined only when reemitting the type context descriptor. --- lib/IRGen/GenDecl.cpp | 1 + lib/IRGen/GenMeta.cpp | 8 +++++--- lib/IRGen/GenThunk.cpp | 5 +++-- lib/IRGen/IRGenModule.h | 11 +++++++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 166c7dc5d1c13..250519e87905f 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1168,6 +1168,7 @@ static void deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, NominalTypeDecl &decl) { + IGM.IRGen.noteLazyReemissionOfNominalTypeDescriptor(&decl); // The type context descriptor depends on canonical metadata records because // pointers to them are attached as trailing objects to it. // diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 88a4224f91168..8108f24f7ad12 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -301,10 +301,12 @@ static void buildMethodDescriptorFields(IRGenModule &IGM, void IRGenModule::emitNonoverriddenMethodDescriptor(const SILVTable *VTable, SILDeclRef declRef) { auto entity = LinkEntity::forMethodDescriptor(declRef); - auto *var = cast(getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo())); - var->setInitializer(nullptr); - + if (!var->isDeclaration()) { + assert(IRGen.isLazilyReemittingNominalTypeDescriptor(VTable->getClass())); + return; + } + ConstantInitBuilder ib(*this); ConstantStructBuilder sb(ib.beginStruct(MethodDescriptorStructTy)); diff --git a/lib/IRGen/GenThunk.cpp b/lib/IRGen/GenThunk.cpp index d18d8846348dc..c3bc0844433ce 100644 --- a/lib/IRGen/GenThunk.cpp +++ b/lib/IRGen/GenThunk.cpp @@ -103,7 +103,7 @@ static FunctionPointer lookupMethod(IRGenFunction &IGF, SILDeclRef declRef) { void IRGenModule::emitDispatchThunk(SILDeclRef declRef) { auto *f = getAddrOfDispatchThunk(declRef, ForDefinition); if (!f->isDeclaration()) { - f->deleteBody(); + return; } IRGenFunction IGF(*this, f); @@ -167,7 +167,8 @@ IRGenModule::getAddrOfMethodLookupFunction(ClassDecl *classDecl, void IRGenModule::emitMethodLookupFunction(ClassDecl *classDecl) { auto *f = getAddrOfMethodLookupFunction(classDecl, ForDefinition); if (!f->isDeclaration()) { - f->deleteBody(); + assert(IRGen.isLazilyReemittingNominalTypeDescriptor(classDecl)); + return; } IRGenFunction IGF(*this, f); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 909b3702eed6a..82590df971d01 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -279,6 +279,8 @@ class IRGenerator { llvm::SmallVector, 4> LazySpecializedTypeMetadataRecords; + llvm::SmallPtrSet LazilyReemittedTypeContextDescriptors; + /// The queue of metadata accessors to emit. /// /// The accessors must be emitted after everything else which might result in @@ -436,6 +438,15 @@ class IRGenerator { return MetadataPrespecializationsForGenericTypes.lookup(type); } + void noteLazyReemissionOfNominalTypeDescriptor(NominalTypeDecl *decl) { + LazilyReemittedTypeContextDescriptors.insert(decl); + } + + bool isLazilyReemittingNominalTypeDescriptor(NominalTypeDecl *decl) { + return LazilyReemittedTypeContextDescriptors.find(decl) != + std::end(LazilyReemittedTypeContextDescriptors); + } + void noteUseOfMetadataAccessor(NominalTypeDecl *decl) { if (LazyMetadataAccessors.count(decl) == 0) { LazyMetadataAccessors.insert(decl); From 40c448514a7dcdf2256ffdd371e178cf9322043c Mon Sep 17 00:00:00 2001 From: Alex Efremov Date: Sat, 15 Aug 2020 19:22:28 +0200 Subject: [PATCH 178/663] [AutoDiff] Support differentiation of non-active `try_apply`. (#33483) Add differentiation support for non-active `try_apply` SIL instructions. Notable pullback generation changes: * Original basic blocks are now visited in a different order: * starting from the original basic block, all its predecessors * are visited in a breadth-first search order. This ensures that * all successors of any block are visited before the block itself. Resolves TF-433. --- .../SILOptimizer/Differentiation/Common.h | 53 ------------ .../Differentiation/PullbackCloner.cpp | 49 +++++++---- .../Differentiation/VJPCloner.cpp | 12 +++ .../Mandatory/Differentiation.cpp | 5 +- .../SILOptimizer/activity_analysis.swift | 16 +++- ...erentiation_control_flow_diagnostics.swift | 14 +++- .../differentiation_control_flow_sil.swift | 53 ++++++------ .../differentiation_diagnostics.swift | 6 -- .../validation-test/control_flow.swift | 81 +++++++++++++++++++ test/AutoDiff/validation-test/optional.swift | 6 +- 10 files changed, 181 insertions(+), 114 deletions(-) diff --git a/include/swift/SILOptimizer/Differentiation/Common.h b/include/swift/SILOptimizer/Differentiation/Common.h index 2f996740b08b6..90e3c26690928 100644 --- a/include/swift/SILOptimizer/Differentiation/Common.h +++ b/include/swift/SILOptimizer/Differentiation/Common.h @@ -271,59 +271,6 @@ inline void createEntryArguments(SILFunction *f) { } } -/// Helper class for visiting basic blocks in post-order post-dominance order, -/// based on a worklist algorithm. -class PostOrderPostDominanceOrder { - SmallVector buffer; - PostOrderFunctionInfo *postOrderInfo; - size_t srcIdx = 0; - -public: - /// Constructor. - /// \p root The root of the post-dominator tree. - /// \p postOrderInfo The post-order info of the function. - /// \p capacity Should be the number of basic blocks in the dominator tree to - /// reduce memory allocation. - PostOrderPostDominanceOrder(DominanceInfoNode *root, - PostOrderFunctionInfo *postOrderInfo, - int capacity = 0) - : postOrderInfo(postOrderInfo) { - buffer.reserve(capacity); - buffer.push_back(root); - } - - /// Get the next block from the worklist. - DominanceInfoNode *getNext() { - if (srcIdx == buffer.size()) - return nullptr; - return buffer[srcIdx++]; - } - - /// Pushes the dominator children of a block onto the worklist in post-order. - void pushChildren(DominanceInfoNode *node) { - pushChildrenIf(node, [](SILBasicBlock *) { return true; }); - } - - /// Conditionally pushes the dominator children of a block onto the worklist - /// in post-order. - template - void pushChildrenIf(DominanceInfoNode *node, Pred pred) { - SmallVector children; - for (auto *child : *node) - children.push_back(child); - llvm::sort(children.begin(), children.end(), - [&](DominanceInfoNode *n1, DominanceInfoNode *n2) { - return postOrderInfo->getPONumber(n1->getBlock()) < - postOrderInfo->getPONumber(n2->getBlock()); - }); - for (auto *child : children) { - SILBasicBlock *childBB = child->getBlock(); - if (pred(childBB)) - buffer.push_back(child); - } - } -}; - /// Cloner that remaps types using the target function's generic environment. class BasicTypeSubstCloner final : public TypeSubstCloner { diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index aa40f16f53d91..c753022f042da 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -1721,22 +1721,36 @@ bool PullbackCloner::Implementation::run() { domOrder.pushChildren(bb); } - // Create pullback blocks and arguments, visiting original blocks in - // post-order post-dominance order. - SmallVector postOrderPostDomOrder; - // Start from the root node, which may have a marker `nullptr` block if - // there are multiple roots. - PostOrderPostDominanceOrder postDomOrder(postDomInfo->getRootNode(), - postOrderInfo, original.size()); - while (auto *origNode = postDomOrder.getNext()) { - auto *origBB = origNode->getBlock(); - postDomOrder.pushChildren(origNode); - // If node is the `nullptr` marker basic block, do not push it. - if (!origBB) - continue; - postOrderPostDomOrder.push_back(origBB); + // Create pullback blocks and arguments, visiting original blocks using BFS + // starting from the original exit block. Unvisited original basic blocks + // (e.g unreachable blocks) are not relevant for pullback generation and thus + // ignored. + // The original blocks in traversal order for pullback generation. + SmallVector originalBlocks; + // The set of visited original blocks. + SmallDenseSet visitedBlocks; + + // Perform BFS from the original exit block. + { + std::deque worklist = {}; + worklist.push_back(origExit); + visitedBlocks.insert(origExit); + while (!worklist.empty()) { + auto *BB = worklist.front(); + worklist.pop_front(); + + originalBlocks.push_back(BB); + + for (auto *nextBB : BB->getPredecessorBlocks()) { + if (!visitedBlocks.count(nextBB)) { + worklist.push_back(nextBB); + visitedBlocks.insert(nextBB); + } + } + } } - for (auto *origBB : postOrderPostDomOrder) { + + for (auto *origBB : originalBlocks) { auto *pullbackBB = pullback.createBasicBlock(); pullbackBBMap.insert({origBB, pullbackBB}); auto pbStructLoweredType = @@ -1801,6 +1815,9 @@ bool PullbackCloner::Implementation::run() { // struct argument. They branch from a pullback successor block to the // pullback original block, passing adjoint values of active values. for (auto *succBB : origBB->getSuccessorBlocks()) { + // Skip generating pullback block for original unreachable blocks. + if (!visitedBlocks.count(succBB)) + continue; auto *pullbackTrampolineBB = pullback.createBasicBlockBefore(pullbackBB); pullbackTrampolineBBMap.insert({{origBB, succBB}, pullbackTrampolineBB}); // Get the enum element type (i.e. the pullback struct type). The enum @@ -1870,7 +1887,7 @@ bool PullbackCloner::Implementation::run() { // Visit original blocks blocks in post-order and perform differentiation // in corresponding pullback blocks. If errors occurred, back out. else { - for (auto *bb : postOrderPostDomOrder) { + for (auto *bb : originalBlocks) { visitSILBasicBlock(bb); if (errorOccurred) return true; diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index ef3980436d9d1..186173e025bc3 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -618,6 +618,18 @@ class VJPCloner::Implementation final getOpValue(origCallee)->getDefiningInstruction()); } + void visitTryApplyInst(TryApplyInst *tai) { + // Build pullback struct value for original block. + auto *pbStructVal = buildPullbackValueStructValue(tai); + // Create a new `try_apply` instruction. + auto args = getOpValueArray<8>(tai->getArguments()); + getBuilder().createTryApply( + tai->getLoc(), getOpValue(tai->getCallee()), + getOpSubstitutionMap(tai->getSubstitutionMap()), args, + createTrampolineBasicBlock(tai, pbStructVal, tai->getNormalBB()), + createTrampolineBasicBlock(tai, pbStructVal, tai->getErrorBB())); + } + void visitDifferentiableFunctionInst(DifferentiableFunctionInst *dfi) { // Clone `differentiable_function` from original to VJP, then add the cloned // instruction to the `differentiable_function` worklist. diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index eb74975008311..083f840e892e7 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -158,8 +158,7 @@ static bool diagnoseNoReturn(ADContext &context, SILFunction *original, /// flow unsupported" error at appropriate source locations. Returns true if /// error is emitted. /// -/// Update as control flow support is added. Currently, branching terminators -/// other than `br`, `cond_br`, `switch_enum` are not supported. +/// Update as control flow support is added. static bool diagnoseUnsupportedControlFlow(ADContext &context, SILFunction *original, DifferentiationInvoker invoker) { @@ -173,7 +172,7 @@ static bool diagnoseUnsupportedControlFlow(ADContext &context, isa(term) || isa(term) || isa(term) || isa(term) || - isa(term)) + isa(term) || isa(term)) continue; // If terminator is an unsupported branching terminator, emit an error. if (term->isBranch()) { diff --git a/test/AutoDiff/SILOptimizer/activity_analysis.swift b/test/AutoDiff/SILOptimizer/activity_analysis.swift index fe8fd1a7785c1..2a2fdcca7f650 100644 --- a/test/AutoDiff/SILOptimizer/activity_analysis.swift +++ b/test/AutoDiff/SILOptimizer/activity_analysis.swift @@ -543,17 +543,25 @@ func activeInoutArgNonactiveInitialResult(_ x: Float) -> Float { func rethrowing(_ x: () throws -> Void) rethrows -> Void {} -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func testTryApply(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} rethrowing({}) return x } // TF-433: differentiation diagnoses `try_apply` before activity info is printed. -// CHECK-NOT: [AD] Activity info for ${{.*}}testTryApply{{.*}} at (parameters=(0) results=(0)) +// CHECK-LABEL: [AD] Activity info for ${{.*}}testTryApply{{.*}} at (parameters=(0) results=(0)) +// CHECK: bb0: +// CHECK: [ACTIVE] %0 = argument of bb0 : $Float +// CHECK: [NONE] // function_ref closure #1 in testTryApply(_:) +// CHECK: [NONE] %3 = convert_function %2 : $@convention(thin) () -> () to $@convention(thin) @noescape () -> () +// CHECK: [NONE] %4 = thin_to_thick_function %3 : $@convention(thin) @noescape () -> () to $@noescape @callee_guaranteed () -> () +// CHECK: [NONE] %5 = convert_function %4 : $@noescape @callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> @error Error +// CHECK: [NONE] // function_ref rethrowing(_:) +// CHECK: bb1: +// CHECK: [NONE] %8 = argument of bb1 : $() +// CHECK: bb2: +// CHECK: [NONE] %10 = argument of bb2 : $Error //===----------------------------------------------------------------------===// // Coroutine differentiation (`begin_apply`) diff --git a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift index 6bc8cda64005f..331a48a425c2c 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift @@ -78,11 +78,8 @@ func nested_loop(_ x: Float) -> Float { func rethrowing(_ x: () throws -> Void) rethrows -> Void {} -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func testTryApply(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} rethrowing({}) return x } @@ -93,10 +90,19 @@ func testTryApply(_ x: Float) -> Float { func withoutDerivative( at x: T, in body: (T) throws -> R ) rethrows -> R { - // expected-note @+1 {{cannot differentiate unsupported control flow}} + // expected-note @+1 {{expression is not differentiable}} try body(x) } +// Tests active `try_apply`. +// expected-error @+1 {{function is not differentiable}} +@differentiable +// expected-note @+1 {{when differentiating this function definition}} +func testNilCoalescing(_ maybeX: Float?) -> Float { + // expected-note @+1 {{expression is not differentiable}} + return maybeX ?? 10 +} + // Test unsupported differentiation of active enum values. // expected-error @+1 {{function is not differentiable}} diff --git a/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift b/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift index 4b30bd64cd358..2778a4d849cd3 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_control_flow_sil.swift @@ -68,29 +68,30 @@ func cond(_ x: Float) -> Float { // CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PULLBACK_REF]]([[BB3_PB_STRUCT]]) // CHECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[ORIG_RES]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) // CHECK-SIL: return [[VJP_RESULT]] +// CHECK-SIL-LABEL: } // end sil function 'AD__cond__vjp_src_0_wrt_0' // CHECK-SIL-LABEL: sil private [ossa] @AD__cond__pullback_src_0_wrt_0 : $@convention(thin) (Float, @owned _AD__cond_bb3__PB__src_0_wrt_0) -> Float { // CHECK-SIL: bb0([[SEED:%.*]] : $Float, [[BB3_PB_STRUCT:%.*]] : @owned $_AD__cond_bb3__PB__src_0_wrt_0): // CHECK-SIL: [[BB3_PRED:%.*]] = destructure_struct [[BB3_PB_STRUCT]] : $_AD__cond_bb3__PB__src_0_wrt_0 -// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_bb3__Pred__src_0_wrt_0, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb3, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb1 +// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_bb3__Pred__src_0_wrt_0, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb1, case #_AD__cond_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb3 -// CHECK-SIL: bb1([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): -// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_bb1__PB__src_0_wrt_0) +// CHECK-SIL: bb1([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): +// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_bb2__PB__src_0_wrt_0) -// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): -// CHECK-SIL: ([[BB1_PRED:%.*]], [[BB1_PB:%.*]]) = destructure_struct [[BB1_PB_STRUCT]] -// CHECK-SIL: [[BB1_ADJVALS:%.*]] = apply [[BB1_PB]]([[SEED]]) : $@callee_guaranteed (Float) -> (Float, Float) -// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_bb1__Pred__src_0_wrt_0, case #_AD__cond_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 - -// CHECK-SIL: bb3([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): -// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_bb2__PB__src_0_wrt_0) - -// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): +// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : @owned $_AD__cond_bb2__PB__src_0_wrt_0): // CHECK-SIL: ([[BB2_PRED:%.*]], [[BB2_PB:%.*]]) = destructure_struct [[BB2_PB_STRUCT]] // CHECK-SIL: [[BB2_ADJVALS:%.*]] = apply [[BB2_PB]]([[SEED]]) : $@callee_guaranteed (Float) -> (Float, Float) // CHECK-SIL: switch_enum [[BB2_PRED]] : $_AD__cond_bb2__Pred__src_0_wrt_0, case #_AD__cond_bb2__Pred__src_0_wrt_0.bb0!enumelt: bb6 +// CHECK-SIL: bb3([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): +// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}}: $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_bb1__PB__src_0_wrt_0) + +// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : @owned $_AD__cond_bb1__PB__src_0_wrt_0): +// CHECK-SIL: ([[BB1_PRED:%.*]], [[BB1_PB:%.*]]) = destructure_struct [[BB1_PB_STRUCT]] +// CHECK-SIL: [[BB1_ADJVALS:%.*]] = apply [[BB1_PB]]([[SEED]]) : $@callee_guaranteed (Float) -> (Float, Float) +// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_bb1__Pred__src_0_wrt_0, case #_AD__cond_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 + // CHECK-SIL: bb5([[BB1_PRED0_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_bb0__PB__src_0_wrt_0): // CHECK-SIL: br bb7({{%.*}} : $Float, [[BB1_PRED0_TRAMP_PB_STRUCT]] : $_AD__cond_bb0__PB__src_0_wrt_0) @@ -99,6 +100,7 @@ func cond(_ x: Float) -> Float { // CHECK-SIL: bb7({{%.*}} : $Float, [[BB0_PB_STRUCT:%.*]] : $_AD__cond_bb0__PB__src_0_wrt_0): // CHECK-SIL: return {{%.*}} : $Float +// CHECK-SIL-LABEL: } // end sil function 'AD__cond__pullback_src_0_wrt_0' @differentiable @_silgen_name("nested_cond") @@ -178,7 +180,7 @@ func enum_notactive(_ e: Enum, _ x: Float) -> Float { // CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PULLBACK_REF]]([[BB3_PB_STRUCT]]) // CHECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[ORIG_RES]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) // CHECK-SIL: return [[VJP_RESULT]] -// CHECK-SIL: } +// CHECK-SIL-LABEL: } // end sil function 'AD__enum_notactive__vjp_src_0_wrt_1' // Test `switch_enum_addr`. @@ -227,7 +229,7 @@ func enum_addr_notactive(_ e: AddressOnlyEnum, _ x: Float) -> Float { // CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PB_FNREF]]<τ_0_0>([[BB3_PB_STRUCT]]) : $@convention(thin) <τ_0_0> (Float, @owned _AD__enum_addr_notactive_bb3__PB__src_0_wrt_1_l<τ_0_0>) -> Float // CHECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[X_ARG]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) // CHECK-SIL: return [[VJP_RESULT]] : $(Float, @callee_guaranteed (Float) -> Float) -// CHECK-SIL: } +// CHECK-SIL-LABEL: } // end sil function 'AD__enum_addr_notactive__vjp_src_0_wrt_1_l' // Test control flow + tuple buffer. // Verify that pullback buffers are not allocated for address projections. @@ -248,25 +250,25 @@ func cond_tuple_var(_ x: Float) -> Float { // CHECK-SIL: [[BB3_PRED:%.*]] = destructure_struct [[BB3_PB_STRUCT]] : $_AD__cond_tuple_var_bb3__PB__src_0_wrt_0 // CHECK-SIL: copy_addr {{%.*}} to {{%.*}} : $*(Float, Float) // CHECK-SIL-NOT: copy_addr {{%.*}} to {{%.*}} : $*Float -// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb3, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb1 +// CHECK-SIL: switch_enum [[BB3_PRED]] : $_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb1, case #_AD__cond_tuple_var_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb3 -// CHECK-SIL: bb1([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): -// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0) +// CHECK-SIL: bb1([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): +// CHECK-SIL: br bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0) -// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): -// CHECK-SIL: [[BB1_PRED:%.*]] = destructure_struct [[BB1_PB_STRUCT]] +// CHECK-SIL: bb2({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): +// CHECK-SIL: [[BB2_PRED:%.*]] = destructure_struct [[BB2_PB_STRUCT]] // CHECK-SIL: copy_addr {{%.*}} to {{%.*}} : $*(Float, Float) // CHECK-SIL-NOT: copy_addr {{%.*}} to {{%.*}} : $*Float -// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 +// CHECK-SIL: switch_enum [[BB2_PRED]] : $_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0.bb0!enumelt: bb6 -// CHECK-SIL: bb3([[BB3_PRED2_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): -// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED2_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0) +// CHECK-SIL: bb3([[BB3_PRED1_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): +// CHECK-SIL: br bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB3_PRED1_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0) -// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB2_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb2__PB__src_0_wrt_0): -// CHECK-SIL: [[BB2_PRED:%.*]] = destructure_struct [[BB2_PB_STRUCT]] +// CHECK-SIL: bb4({{%.*}} : $Float, {{%.*}} : $Float, [[BB1_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb1__PB__src_0_wrt_0): +// CHECK-SIL: [[BB1_PRED:%.*]] = destructure_struct [[BB1_PB_STRUCT]] // CHECK-SIL: copy_addr {{%.*}} to {{%.*}} : $*(Float, Float) // CHECK-SIL-NOT: copy_addr {{%.*}} to {{%.*}} : $*Float -// CHECK-SIL: switch_enum [[BB2_PRED]] : $_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb2__Pred__src_0_wrt_0.bb0!enumelt: bb6 +// CHECK-SIL: switch_enum [[BB1_PRED]] : $_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0, case #_AD__cond_tuple_var_bb1__Pred__src_0_wrt_0.bb0!enumelt: bb5 // CHECK-SIL: bb5([[BB1_PRED0_TRAMP_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb0__PB__src_0_wrt_0): // CHECK-SIL: br bb7({{%.*}} : $Float, [[BB1_PRED0_TRAMP_PB_STRUCT]] : $_AD__cond_tuple_var_bb0__PB__src_0_wrt_0) @@ -276,3 +278,4 @@ func cond_tuple_var(_ x: Float) -> Float { // CHECK-SIL: bb7({{%.*}} : $Float, [[BB0_PB_STRUCT:%.*]] : $_AD__cond_tuple_var_bb0__PB__src_0_wrt_0): // CHECK-SIL: return {{%.*}} : $Float +// CHECK-SIL-LABEL: } // end sil function 'AD__cond_tuple_var__pullback_src_0_wrt_0' diff --git a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift index 9473311a62247..cbb4e0fa132f7 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift @@ -32,22 +32,16 @@ func conditional(_ x: Float, _ flag: Bool) -> Float { func throwing() throws -> Void {} -// expected-error @+2 {{function is not differentiable}} -// expected-note @+2 {{when differentiating this function definition}} @differentiable func try_apply(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} try! throwing() return x } func rethrowing(_ x: () throws -> Void) rethrows -> Void {} -// expected-error @+2 {{function is not differentiable}} -// expected-note @+2 {{when differentiating this function definition}} @differentiable func try_apply_rethrows(_ x: Float) -> Float { - // expected-note @+1 {{cannot differentiate unsupported control flow}} rethrowing({}) return x } diff --git a/test/AutoDiff/validation-test/control_flow.swift b/test/AutoDiff/validation-test/control_flow.swift index d2042a1135216..ea3dff8e0ba2a 100644 --- a/test/AutoDiff/validation-test/control_flow.swift +++ b/test/AutoDiff/validation-test/control_flow.swift @@ -736,4 +736,85 @@ ControlFlowTests.test("BranchingCastInstructions") { expectEqual((3, 1), valueWithGradient(at: Float(3), in: conditionalCast)) } +ControlFlowTests.test("ThrowingCalls") { + // TF-433: Test non-active `try_apply` differentiation. + func throwing() throws -> Void {} + + @differentiable + func testThrowing(_ x: Float) -> Float { + try! throwing() + return x + } + expectEqual(10, pullback(at: 3, in: testThrowing)(10)) + + @differentiable + func testThrowingGeneric(_ x: T) -> T { + try! throwing() + return x + } + expectEqual(10, pullback(at: 3, in: testThrowingGeneric)(10)) + + func rethrowing(_ body: () throws -> Void) rethrows -> Void {} + + @differentiable + func testRethrowingIdentity(_ x: Float) -> Float { + rethrowing({}) // non-active `try_apply` + return x + } + expectEqual(10, pullback(at: 3, in: testRethrowingIdentity)(10)) + + @differentiable + func testRethrowingIdentityGeneric(_ x: T) -> T { + rethrowing({}) // non-active `try_apply` + return x + } + expectEqual(10, pullback(at: 3, in: testRethrowingIdentityGeneric)(10)) + + @differentiable + func testComplexControlFlow(_ x: Float) -> Float { + rethrowing({}) + for _ in 0..(_ x: T) -> T { + rethrowing({}) + for _ in 0..<10 { + if true { + rethrowing({}) + } + rethrowing({}) // non-active `try_apply` + } + rethrowing({}) + return x + } + expectEqual(10, pullback(at: 3, in: testComplexControlFlowGeneric)(10)) + + // Test `Array.map(_:)`, which is rethrowing. + func testArrayMap(_ x: [Float]) -> [Float] { + let max = x.map { $0 }.max()! // non-active `try_apply` + _blackHole(max) + return x + } + expectEqual([10, 10], pullback(at: [2, 3], in: testArrayMap)([10, 10])) + + // Test `Bool.&&(_:)`, which is rethrowing. + func testBooleanShortCircuitingOperations(_ x: Float, bool: Bool) -> Float { + if bool && bool || bool { // non-active `try_apply` + return x * x + } + return x + x + } + expectEqual(6, gradient(at: 3, in: { x in testBooleanShortCircuitingOperations(x, bool: true) })) + expectEqual(2, gradient(at: 3, in: { x in testBooleanShortCircuitingOperations(x, bool: false) })) +} + runAllTests() diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift index 4aeb60ba42762..455fa091e9e67 100644 --- a/test/AutoDiff/validation-test/optional.swift +++ b/test/AutoDiff/validation-test/optional.swift @@ -10,11 +10,11 @@ var OptionalTests = TestSuite("OptionalDifferentiation") // Basic tests. //===----------------------------------------------------------------------===// + +// TODO(TF-433): operator `??` lowers to an active `try_apply`. /* -// TODO(TF-433): operator `??` lowers to `try_apply` instead of `switch_enum`, -// which is not yet supported by differentiation. @differentiable -func optional1(_ maybeX: Float?) -> Float { +func optional_nil_coalescing(_ maybeX: Float?) -> Float { return maybeX ?? 10 } */ From b1eccb594de8f10b9e19a753349bbd9c4f1045d1 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sun, 16 Aug 2020 12:27:21 -0300 Subject: [PATCH 179/663] [Sema] Do not diagnose contextual type mismatches for malformed key path expressions (#33230) * [AST] Adding hasSingleInvalidComponent to key path expression * [Sema] Adding a new fix and failure to diagnose missing key path component * [Sema] Recording new fix for key path missing components and remove diagnose from pre-check * [tests] Adjusting key path missing component contextual tests * [Sema] Renaming missing component key path fix and failure * [Sema] Correcting comments typos --- include/swift/AST/Expr.h | 8 +++++++- lib/Sema/CSBindings.cpp | 6 ++++++ lib/Sema/CSDiagnostics.cpp | 16 ++++++++++++++++ lib/Sema/CSDiagnostics.h | 14 ++++++++++++++ lib/Sema/CSFix.cpp | 12 ++++++++++++ lib/Sema/CSFix.h | 24 +++++++++++++++++++++++- lib/Sema/CSSimplify.cpp | 11 ++++++++++- lib/Sema/TypeCheckConstraints.cpp | 1 - test/expr/unary/keypath/keypath.swift | 12 +++++++----- 9 files changed, 95 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 0e6e4070b158b..6e9b24921b1ff 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -5657,7 +5657,13 @@ class KeyPathExpr : public Expr { /// components from the argument array. void resolveComponents(ASTContext &C, ArrayRef resolvedComponents); - + + /// Indicates if the key path expression is composed by a single invalid + /// component. e.g. missing component `\Root` + bool hasSingleInvalidComponent() const { + return Components.size() == 1 && !Components.front().isValid(); + } + /// Retrieve the string literal expression, which will be \c NULL prior to /// type checking and a string literal after type checking for an /// @objc key path. diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index ae90bf022d98a..7e7f3a3ffde8f 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -1210,6 +1210,12 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const { } else if (srcLocator->directlyAt()) { fix = SpecifyObjectLiteralTypeImport::create(cs, dstLocator); } else if (srcLocator->isKeyPathRoot()) { + // If we recorded an invalid key path fix, let's skip this specify root + // type fix because it wouldn't produce a useful diagnostic. + auto *kpLocator = cs.getConstraintLocator(srcLocator->getAnchor()); + if (cs.hasFixFor(kpLocator, FixKind::AllowKeyPathWithoutComponents)) + return true; + fix = SpecifyKeyPathRootType::create(cs, dstLocator); } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 09087ae89470a..80bcf26c217d0 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -6760,3 +6760,19 @@ void TrailingClosureRequiresExplicitLabel::fixIt( diagnostic.fixItInsert(newRParenLoc, isExpr(anchor) ? "]" : ")"); } + +bool InvalidEmptyKeyPathFailure::diagnoseAsError() { + auto *KPE = getAsExpr(getAnchor()); + assert(KPE && KPE->hasSingleInvalidComponent() && + "Expected a malformed key path expression"); + + // If we have a string interpolation represented as key path expressions + // e.g. \(x), \(x, a: 1). Let's skip it because this would be already + // diagnosed and it is not the case for an extra empty key path diagnostic. + auto *root = KPE->getParsedRoot(); + if (root && (isa(root) || isa(root))) + return true; + + emitDiagnostic(diag::expr_swift_keypath_empty); + return true; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 9786056f334a9..e1c925322d495 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -2248,6 +2248,20 @@ class TrailingClosureRequiresExplicitLabel final : public FailureDiagnostic { const FunctionArgApplyInfo &info) const; }; +/// Diagnose situations where we have a key path with no components. +/// +/// \code +/// let _ : KeyPath = \A +/// \endcode +class InvalidEmptyKeyPathFailure final : public FailureDiagnostic { +public: + InvalidEmptyKeyPathFailure(const Solution &solution, + ConstraintLocator *locator) + : FailureDiagnostic(solution, locator) {} + + bool diagnoseAsError() override; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 96f6a43872284..2718add47959c 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1539,3 +1539,15 @@ SpecifyLabelToAssociateTrailingClosure::create(ConstraintSystem &cs, return new (cs.getAllocator()) SpecifyLabelToAssociateTrailingClosure(cs, locator); } + +bool AllowKeyPathWithoutComponents::diagnose(const Solution &solution, + bool asNote) const { + InvalidEmptyKeyPathFailure failure(solution, getLocator()); + return failure.diagnose(asNote); +} + +AllowKeyPathWithoutComponents * +AllowKeyPathWithoutComponents::create(ConstraintSystem &cs, + ConstraintLocator *locator) { + return new (cs.getAllocator()) AllowKeyPathWithoutComponents(cs, locator); +} diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 8ce3c43a103af..c834561b99262 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -266,13 +266,16 @@ enum class FixKind : uint8_t { /// Specify key path root type when it cannot be infered from context. SpecifyKeyPathRootType, - + /// Unwrap optional base on key path application. UnwrapOptionalBaseKeyPathApplication, /// Explicitly specify a label to match trailing closure to a certain /// parameter in the call. SpecifyLabelToAssociateTrailingClosure, + + /// Allow key path expressions with no components. + AllowKeyPathWithoutComponents, }; class ConstraintFix { @@ -1958,6 +1961,25 @@ class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix { create(ConstraintSystem &cs, ConstraintLocator *locator); }; +/// Diagnose situations where we have a key path with no components. +/// +/// \code +/// let _ : KeyPath = \A +/// \endcode +class AllowKeyPathWithoutComponents final : public ConstraintFix { + AllowKeyPathWithoutComponents(ConstraintSystem &cs, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::AllowKeyPathWithoutComponents, locator) {} + +public: + std::string getName() const override { return "key path missing component"; } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + static AllowKeyPathWithoutComponents *create(ConstraintSystem &cs, + ConstraintLocator *locator); +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1e9e1e969596f..637e9757797fd 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -8127,6 +8127,14 @@ ConstraintSystem::simplifyKeyPathConstraint( if (keyPathTy->isHole()) return SolutionKind::Solved; + // If we have a malformed KeyPathExpr e.g. let _: KeyPath = \A + // let's record a AllowKeyPathMissingComponent fix. + if (keyPath->hasSingleInvalidComponent()) { + auto *fix = AllowKeyPathWithoutComponents::create( + *this, getConstraintLocator(locator)); + return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; + } + // If the root type has been bound to a hole, we cannot infer it. if (getFixedTypeRecursive(rootTy, /*wantRValue*/ true)->isHole()) return SolutionKind::Solved; @@ -9988,7 +9996,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::UnwrapOptionalBaseKeyPathApplication: case FixKind::AllowCoercionToForceCast: case FixKind::SpecifyKeyPathRootType: - case FixKind::SpecifyLabelToAssociateTrailingClosure: { + case FixKind::SpecifyLabelToAssociateTrailingClosure: + case FixKind::AllowKeyPathWithoutComponents: { return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index b0301f2fb8d76..bcafe3d4d6bee 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -1900,7 +1900,6 @@ void PreCheckExpression::resolveKeyPathExpr(KeyPathExpr *KPE) { // Key paths must be spelled with at least one component. if (components.empty()) { - DE.diagnose(KPE->getLoc(), diag::expr_swift_keypath_empty); // Passes further down the pipeline expect keypaths to always have at least // one component, so stuff an invalid component in the AST for recovery. components.push_back(KeyPathExpr::Component()); diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index d6fd26dade0f4..94b1824038e4f 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -36,7 +36,7 @@ struct A: Hashable { func hash(into hasher: inout Hasher) { fatalError() } } struct B {} -struct C { // expected-note 3 {{'T' declared as parameter to type 'C'}} +struct C { // expected-note 4 {{'T' declared as parameter to type 'C'}} var value: T subscript() -> T { get { return value } } subscript(sub: Sub) -> T { get { return value } set { } } @@ -224,15 +224,17 @@ func testKeyPathInGenericContext(hashable: H, anything: X) { } func testDisembodiedStringInterpolation(x: Int) { - \(x) // expected-error{{string interpolation}} expected-error{{}} - \(x, radix: 16) // expected-error{{string interpolation}} expected-error{{}} + \(x) // expected-error{{string interpolation can only appear inside a string literal}} + \(x, radix: 16) // expected-error{{string interpolation can only appear inside a string literal}} } func testNoComponents() { let _: KeyPath = \A // expected-error{{must have at least one component}} - let _: KeyPath = \C // expected-error{{must have at least one component}} expected-error{{}} + let _: KeyPath = \C // expected-error{{must have at least one component}} // expected-error@-1 {{generic parameter 'T' could not be inferred}} - // expected-error@-2 {{cannot convert value of type 'KeyPath' to specified type 'KeyPath, A>'}} + let _: KeyPath = \A // expected-error{{must have at least one component}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + _ = \A // expected-error {{key path must have at least one component}} } struct TupleStruct { From c7d33b4f3bede7391c458b200d8ca1cc0646a99f Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Sun, 16 Aug 2020 12:56:47 -0700 Subject: [PATCH 180/663] -enable-cxx-interop is not a common frontend option --- lib/Driver/ToolChains.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index c6513efe2bf45..ea831c05052e6 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -212,7 +212,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_require_explicit_availability_target); inputArgs.AddLastArg(arguments, options::OPT_enable_testing); inputArgs.AddLastArg(arguments, options::OPT_enable_private_imports); - inputArgs.AddLastArg(arguments, options::OPT_enable_cxx_interop); inputArgs.AddLastArg(arguments, options::OPT_g_Group); inputArgs.AddLastArg(arguments, options::OPT_debug_info_format); inputArgs.AddLastArg(arguments, options::OPT_import_underlying_module); From a0333a4e370fbdf386a67d980e93bc524f97b532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez=20Troiti=C3=B1o?= Date: Sun, 16 Aug 2020 16:15:56 -0700 Subject: [PATCH 181/663] [android] XFAIL opt-remark-generator.swift in ARMv7 Android ARMv7 doesn't seem to simplify the remarks from Optional to just SubKlass, while other platforms do. I did not find any clues in #33171 what it might be happening, so XFAIL the test to avoid a failing build. --- test/SILOptimizer/opt-remark-generator.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/SILOptimizer/opt-remark-generator.swift b/test/SILOptimizer/opt-remark-generator.swift index ed32d18dae885..1991d1a083f8c 100644 --- a/test/SILOptimizer/opt-remark-generator.swift +++ b/test/SILOptimizer/opt-remark-generator.swift @@ -1,6 +1,8 @@ // RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify // REQUIRES: optimized_stdlib +// XFAIL: OS=linux-androideabi && CPU=armv7 + public class Klass {} public var global = Klass() From 1ec1c0ef48d100bfcc50efae8ff068788b22d4d4 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Sun, 16 Aug 2020 20:13:54 -0700 Subject: [PATCH 182/663] Remove all comments related to 'insertion points' in ARCSequenceOpts Historically ARC code motion was also part of ARCSequenceOpts. Remove some stale comments regarding 'insertion points' --- lib/SILOptimizer/ARC/ARCMatchingSet.cpp | 8 +------- lib/SILOptimizer/ARC/ARCRegionState.cpp | 7 +++---- lib/SILOptimizer/ARC/ARCSequenceOpts.cpp | 9 ++------- lib/SILOptimizer/ARC/RefCountState.cpp | 6 ------ 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp index 442a4c9011b89..fc603c690f747 100644 --- a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp +++ b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp @@ -68,8 +68,6 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() { continue; } - // We need to be known safe over all increments/decrements we are matching - // up to ignore insertion points. bool BUIsKnownSafe = (*BURefCountState)->second.isKnownSafe(); LLVM_DEBUG(llvm::dbgs() << " BOTTOM UP KNOWNSAFE: " << (BUIsKnownSafe ? "true" : "false") << "\n"); @@ -152,8 +150,6 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() { continue; } - // We need to be known safe over all increments/decrements we are matching - // up to ignore insertion points. bool TDIsKnownSafe = (*TDRefCountState)->second.isKnownSafe(); LLVM_DEBUG(llvm::dbgs() << " TOP DOWN KNOWNSAFE: " << (TDIsKnownSafe ? "true" : "false") << "\n"); @@ -223,7 +219,7 @@ bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() { LLVM_DEBUG(llvm::dbgs() << "Attempting to match up increments -> " "decrements:\n"); // For each increment in our list of new increments, attempt to match them - // up with decrements and gather the insertion points of the decrements. + // up with decrements. auto Result = matchIncrementsToDecrements(); if (!Result) { LLVM_DEBUG(llvm::dbgs() << " FAILED TO MATCH INCREMENTS -> " @@ -287,8 +283,6 @@ bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() { assert(MatchSet.Increments.empty() == MatchSet.Decrements.empty() && "Match set without increments or decrements"); - // If we do not have any insertion points but we do have increments, we must - // be eliminating pairs. if (!MatchSet.Increments.empty()) MatchedPair = true; diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index f654bbeb6e485..783ddf60b7cab 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -188,7 +188,7 @@ static bool isARCSignificantTerminator(TermInst *TI) { // Visit each one of our predecessor regions and see if any are blocks that can // use reference counted values. If any of them do, we advance the sequence for -// the pointer and create an insertion point here. This state will be propagated +// the pointer. This state will be propagated // into all of our predecessors, allowing us to be conservatively correct in all // cases. // @@ -305,9 +305,8 @@ bool ARCRegionState::processBlockBottomUp( // Now visit each one of our predecessor regions and see if any are blocks // that can use reference counted values. If any of them do, we advance the - // sequence for the pointer and create an insertion point here. This state - // will be propagated into all of our predecessors, allowing us to be - // conservatively correct in all cases. + // sequence for the pointer. This state will be propagated into all of our + // predecessors, allowing us to be conservatively correct in all cases. processBlockBottomUpPredTerminators(R, AA, LRFI, SetFactory); return NestingDetected; diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index 00d284761f6a7..450fc808d88e6 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -45,10 +45,8 @@ llvm::cl::opt EnableLoopARC("enable-loop-arc", llvm::cl::init(false)); // Code Motion //===----------------------------------------------------------------------===// -// This routine takes in the ARCMatchingSet \p MatchSet and inserts new -// increments, decrements at the insertion points and adds the old increment, -// decrements to the delete list. Sets changed to true if anything was moved or -// deleted. +// This routine takes in the ARCMatchingSet \p MatchSet and adds the increments +// and decrements to the delete list. void ARCPairingContext::optimizeMatchingSet( ARCMatchingSet &MatchSet, llvm::SmallVectorImpl &NewInsts, llvm::SmallVectorImpl &DeadInsts) { @@ -99,9 +97,6 @@ bool ARCPairingContext::performMatching( for (auto *I : Set.Decrements) DecToIncStateMap.erase(I); - // Add the Set to the callback. *NOTE* No instruction destruction can - // happen here since we may remove instructions that are insertion points - // for other instructions. optimizeMatchingSet(Set, NewInsts, DeadInsts); } } diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index e0c43fed19040..2406236c6851d 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -241,14 +241,11 @@ bool BottomUpRefCountState::handleGuaranteedUser( // Advance the sequence... switch (LatState) { - // If were decremented, insert the insertion point. case LatticeState::Decremented: { LatState = LatticeState::MightBeDecremented; return true; } case LatticeState::MightBeUsed: - // If we have a might be used, we already created an insertion point - // earlier. Just move to MightBeDecremented. LatState = LatticeState::MightBeDecremented; return true; case LatticeState::MightBeDecremented: @@ -705,14 +702,11 @@ bool TopDownRefCountState::handleGuaranteedUser( "Must be able to be used at this point of the lattice."); // Advance the sequence... switch (LatState) { - // If were decremented, insert the insertion point. case LatticeState::Incremented: { LatState = LatticeState::MightBeUsed; return true; } case LatticeState::MightBeDecremented: - // If we have a might be used, we already created an insertion point - // earlier. Just move to MightBeDecremented. LatState = LatticeState::MightBeUsed; return true; case LatticeState::MightBeUsed: From 4a429d0ac77e36eee33c7787d8b11ef2711c6988 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Mon, 17 Aug 2020 12:00:06 +0200 Subject: [PATCH 183/663] [Diag] Refactor `diagnosticStringFor` to return StringRef Signed-off-by: HassanElDesouky --- include/swift/AST/DiagnosticEngine.h | 4 +++- lib/AST/DiagnosticEngine.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index ee3c776cd9db6..2b3c135d7b0db 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/LocalizationFormat.h" #include "swift/AST/TypeLoc.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/FileSystem.h" @@ -987,7 +988,8 @@ namespace swift { void emitTentativeDiagnostics(); public: - const char *diagnosticStringFor(const DiagID id, bool printDiagnosticName); + llvm::StringRef diagnosticStringFor(const DiagID id, + bool printDiagnosticName); /// If there is no clear .dia file for a diagnostic, put it in the one /// corresponding to the SourceLoc given here. diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 9e0094d02b279..5719cc55f62d2 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -1010,8 +1010,9 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { emitDiagnostic(childNote); } -const char *DiagnosticEngine::diagnosticStringFor(const DiagID id, - bool printDiagnosticName) { +llvm::StringRef +DiagnosticEngine::diagnosticStringFor(const DiagID id, + bool printDiagnosticName) { // TODO: Print diagnostic names from `localization`. if (printDiagnosticName) { return debugDiagnosticStrings[(unsigned)id]; @@ -1020,7 +1021,7 @@ const char *DiagnosticEngine::diagnosticStringFor(const DiagID id, if (localization) { auto localizedMessage = localization.get()->getMessageOr(id, defaultMessage); - return localizedMessage.data(); + return localizedMessage; } return defaultMessage; } From c2374f0fc383d6cd608c682abd9be32f6b5da953 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Sun, 16 Aug 2020 22:34:09 -0700 Subject: [PATCH 184/663] Add unit test for ARCSequenceOpts with optimizable arc ops around try_apply --- test/SILOptimizer/arcsequenceopts.sil | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/SILOptimizer/arcsequenceopts.sil b/test/SILOptimizer/arcsequenceopts.sil index 8825d9cbae7f0..b12c341ed0de9 100644 --- a/test/SILOptimizer/arcsequenceopts.sil +++ b/test/SILOptimizer/arcsequenceopts.sil @@ -405,6 +405,12 @@ bb0(%0 : $<τ_0_0> { var τ_0_0 } ): return %1 : $() } +sil @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error Error { +bb0(%0 : $<τ_0_0> { var τ_0_0 } ): + %1 = tuple () + return %1 : $() +} + // CHECK_LABEL: sil hidden [noinline] @$test_guaranteed_call : // CHECK: bb1{{.*}}: // CHECK-NOT: strong_retain @@ -2157,6 +2163,30 @@ bb2(%4 : $Error): throw %4 : $Error } +// CHECK_LABEL: sil hidden [noinline] @$try_apply_test_3 : +// CHECK-NOT: strong_retain +// CHECK-NOT: strong_release +// CHECK_LABEL: } // end sil function '$try_apply_test_3' +sil hidden [noinline] @$try_apply_test_3 : $@convention(thin) () -> @error Error { +bb0: + %box = alloc_box $<τ_0_0> { var τ_0_0 } + %proj = project_box %box : $<τ_0_0> { var τ_0_0 } , 0 + %funcref = function_ref @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error Error + br bb1 + +bb1: + strong_retain %box : $<τ_0_0> { var τ_0_0 } + try_apply %funcref (%box) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error Error, normal bbs, error bbe + +bbs(%s : $()): + strong_release %box : $<τ_0_0> { var τ_0_0 } + return undef : $() + +bbe(%e : $Error): + strong_release %box : $<τ_0_0> { var τ_0_0 } + throw %e : $Error +} + // In this control flow, ARC runs multiple iterations to get rid of and move the retain and releases. // In the first iteration, we will try to move id1/id3 towards each other. // we create new instructions and remove the old ones. However we had a bug to insert these newly created From 14ad9cc11c73a5de10b21a473f1599a7a6ef0c32 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 17 Aug 2020 11:54:03 -0700 Subject: [PATCH 185/663] build: add a builder script for the rebranch --- utils/build-windows-rebranch.bat | 346 +++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 utils/build-windows-rebranch.bat diff --git a/utils/build-windows-rebranch.bat b/utils/build-windows-rebranch.bat new file mode 100644 index 0000000000000..1b2023bf2b1c5 --- /dev/null +++ b/utils/build-windows-rebranch.bat @@ -0,0 +1,346 @@ +:: build-windows.bat +:: +:: This source file is part of the Swift.org open source project +:: +:: Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +:: Licensed under Apache License v2.0 with Runtime Library Exception +:: +:: See https://swift.org/LICENSE.txt for license information +:: See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +:: REQUIRED ENVIRONMENT VARIABLES +:: This script requires to be executed inside one Visual Studio command line, +:: in order for many of the tools and environment variables to be available. +:: Additionally, it needs the following variables: +:: - CMAKE_BUILD_TYPE: Kind of build: Release, RelWithDebInfo, Debug. +:: - PYTHON_HOME: The Python installation directory. + +:: REQUIRED PERMISSIONS +:: Practically, it is easier to be in the Adminstrators group to run the +:: script, but it should be possible to execute as a normal user. +:: The user will need permission to write files into the Windows SDK and the +:: VisualC++ folder. + +:: @echo off + +setlocal enableextensions enabledelayedexpansion + +set icu_version_major=64 +set icu_version_minor=2 +set icu_version=%icu_version_major%_%icu_version_minor% +set icu_version_dashed=%icu_version_major%-%icu_version_minor% + +set "exitOnError=|| (exit /b)" +set current_directory=%~dp0 +set current_directory=%current_directory:~0,-1% +set source_root=%current_directory%\..\.. + +:: Resetting source_root with %CD% removes the ..\.. from the paths, and makes +:: the output easier to read. +cd %source_root% +set source_root=%CD% + +set full_build_root=%source_root%\build +mkdir %full_build_root% + +:: Use the shortest path we can for the build directory, to avoid Windows +:: path problems as much as we can. +subst T: /d +subst T: %full_build_root% %exitOnError% +set build_root=T: +set install_directory=%build_root%\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr + +md %build_root%\tmp +set TMPDIR=%build_root%\tmp + +md %build_root%\tmp\org.llvm.clang +set CUSTOM_CLANG_MODULE_CACHE=%build_root%\tmp\org.llvm.clang.9999 + +md %build_root%\tmp\org.swift.package-manager +set SWIFTPM_MODULECACHE_OVERRIDE=%build_root%\tmp\org.swift.package-manager + +call :clone_repositories %exitOnError% +call :download_icu %exitOnError% +:: TODO: Disabled until we need LLBuild/SwiftPM in this build script. +:: call :download_sqlite3 + +call :build_llvm %exitOnError% +path %PATH%;%install_directory%\bin + +call :build_cmark %exitOnError% + +call :prepare_platform_modules %exitOnError% +call :build_swift %exitOnError% + +call :build_lldb %exitOnError% + +call :build_libdispatch %exitOnError% + +path %source_root%\icu-%icu_version%\bin64;%install_directory%\bin;%build_root%\swift\bin;%build_root%\swift\libdispatch-prefix\bin;%PATH%;C:\Program Files\Git\usr\bin +call :test_swift %exitOnError% +call :test_libdispatch %exitOnError% + +goto :end +endlocal + +:clone_repositories +:: Clones the repositories used by the Windows build. +:: It supposes that the swift repository is already cloned by CI. +:: It supposes the %CD% is the source root. +setlocal enableextensions enabledelayedexpansion + +git -C "%source_root%\swift" config --local core.autocrlf input +git -C "%source_root%\swift" config --local core.symlink true +git -C "%source_root%\swift" checkout-index --force --all + +git clone --depth 1 --single-branch https://github.com/apple/swift-cmark cmark %exitOnError% +git clone --depth 1 --single-branch --branch swift/master-rebranch https://github.com/apple/llvm-project llvm-project %exitOnError% +mklink /D "%source_root%\clang" "%source_root%\llvm-project\clang" +mklink /D "%source_root%\llvm" "%source_root%\llvm-project\llvm" +mklink /D "%source_root%\lld" "%source_root%\llvm-project\lld" +mklink /D "%source_root%\lldb" "%source_root%\llvm-project\lldb" +mklink /D "%source_root%\compiler-rt" "%source_root%\llvm-project\compiler-rt" +mklink /D "%source_root%\libcxx" "%source_root%\llvm-project\libcxx" +mklink /D "%source_root%\clang-tools-extra" "%source_root%\llvm-project\clang-tools-extra" +git clone --depth 1 --single-branch https://github.com/apple/swift-corelibs-libdispatch %exitOnError% + +goto :eof +endlocal + + +:download_icu +:: Downloads ICU, which will be used as a dependency for the Swift Standard +:: Library and Foundation. +setlocal enableextensions enabledelayedexpansion + +set file_name=icu4c-%icu_version%-Win64-MSVC2017.zip +curl -L -O "https://github.com/unicode-org/icu/releases/download/release-%icu_version_dashed%/%file_name%" %exitOnError% +:: unzip warns about the paths in the zip using slashes, which raises the +:: errorLevel to 1. We cannot use exitOnError, and have to ignore errors. +"C:\Program Files\Git\usr\bin\unzip.exe" -o %file_name% -d "%source_root%\icu-%icu_version%" +exit /b 0 + +goto :eof +endlocal + + +:download_sqlite3 +:: Downloads SQLite3, which will be used as a dependency for llbuild and +:: Swift Package Manager. +setlocal enableextensions enabledelayedexpansion + +set file_name=sqlite-amalgamation-3270200.zip +curl -L -O "https://www.sqlite.org/2019/%file_name%" %exitOnError% +"C:\Program Files\Git\usr\bin\unzip.exe" -o %file_name% %exitOnError% + +goto :eof +endlocal + + +:prepare_platform_modules +:: Create files into the right places of the Windows SDK to the files in the +:: swift repository, in order to consider the headers of the Windows SDK a +:: module to compile Swift code against them. +setlocal enableextensions enabledelayedexpansion + +copy /y "%source_root%\swift\stdlib\public\Platform\ucrt.modulemap" "%UniversalCRTSdkDir%\Include\%UCRTVersion%\ucrt\module.modulemap" %exitOnError% +copy /y "%source_root%\swift\stdlib\public\Platform\winsdk.modulemap" "%UniversalCRTSdkDir%\Include\%UCRTVersion%\um\module.modulemap" %exitOnError% +copy /y "%source_root%\swift\stdlib\public\Platform\visualc.modulemap" "%VCToolsInstallDir%\include\module.modulemap" %exitOnError% +copy /y "%source_root%\swift\stdlib\public\Platform\visualc.apinotes" "%VCToolsInstallDir%\include\visualc.apinotes" %exitOnError% + +goto :eof +endlocal + + +:build_llvm +:: Configures, builds, and installs LLVM +setlocal enableextensions enabledelayedexpansion + +cmake^ + -B "%build_root%\llvm"^ + -G Ninja^ + -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ + -DCMAKE_C_COMPILER=cl^ + -DCMAKE_CXX_COMPILER=cl^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ + -DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-windows-msvc^ + -DLLVM_ENABLE_PDB:BOOL=YES^ + -DLLVM_ENABLE_ASSERTIONS:BOOL=YES^ + -DLLVM_ENABLE_PROJECTS:STRING=lld;clang^ + -DLLVM_TARGETS_TO_BUILD:STRING="AArch64;ARM;X86"^ + -DLLVM_INCLUDE_BENCHMARKS:BOOL=NO^ + -DLLVM_INCLUDE_DOCS:BOOL=NO^ + -DLLVM_INCLUDE_EXAMPLES:BOOL=NO^ + -DLLVM_INCLUDE_GO_TESTS:BOOL=NO^ + -DLLVM_TOOL_GOLD_BUILD:BOOL=NO^ + -DLLVM_ENABLE_OCAMLDOC:BOOL=NO^ + -DLLVM_ENABLE_LIBXML2:BOOL=NO^ + -DLLVM_ENABLE_ZLIB:BOOL=NO^ + -DENABLE_X86_RELAX_RELOCATIONS:BOOL=YES^ + -DLLVM_INSTALL_BINUTILS_SYMLINKS:BOOL=YES^ + -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ + -DLLVM_TOOLCHAIN_TOOLS:STRING="addr2line;ar;c++filt;dsymutil;dwp;llvm-ar;llvm-cov;llvm-cvtres;llvm-cxxfilt;llvm-dlltool;llvm-dwp;llvm-ranlib;llvm-lib;llvm-mt;llvm-nm;llvm-objdump;llvm-pdbutil;llvm-profdata;llvm-rc;llvm-readelf;llvm-readobj;llvm-size;llvm-strip;llvm-symbolizer;llvm-undname;nm;objcopy;objdump;ranlib;readelf;size;strings"^ + -DCLANG_TOOLS="clang;clang-format;clang-headers;clang-tidy"^ + -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ + -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -S "%source_root%\llvm" %exitOnError% + +cmake --build "%build_root%\llvm" %exitOnError% +cmake --build "%build_root%\llvm" --target install %exitOnError% + +goto :eof +endlocal + + +:build_cmark +:: Configures and builds CMark +setlocal enableextensions enabledelayedexpansion + +cmake^ + -B "%build_root%\cmark"^ + -G Ninja^ + -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ + -DCMAKE_C_COMPILER=cl^ + -DCMAKE_CXX_COMPILER=cl^ + -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ + -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -S "%source_root%\cmark" %exitOnError% + +cmake --build "%build_root%\cmark" %exitOnError% + +goto :eof +endlocal + + +:build_swift +:: Configures, builds, and installs Swift and the Swift Standard Library +setlocal enableextensions enabledelayedexpansion + +:: SWIFT_PARALLEL_LINK_JOBS=8 allows the build machine to use as many CPU as +:: possible, while not exhausting the RAM. +cmake^ + -B "%build_root%\swift"^ + -G Ninja^ + -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ + -DCMAKE_C_COMPILER=cl^ + -DCMAKE_CXX_COMPILER=cl^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ + -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ + -DSWIFT_PATH_TO_CMARK_BUILD:PATH=%build_root%\cmark^ + -DSWIFT_PATH_TO_CMARK_SOURCE:PATH=%source_root%\cmark^ + -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH=%source_root%\swift-corelibs-libdispatch^ + -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ + -DSWIFT_INCLUDE_DOCS:BOOL=NO^ + -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE:PATH=%source_root%\icu-%icu_version%\include\unicode^ + -DSWIFT_WINDOWS_x86_64_ICU_UC:PATH=%source_root%\icu-%icu_version%\lib64\icuuc.lib^ + -DSWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE:PATH=%source_root%\icu-%icu_version%\include^ + -DSWIFT_WINDOWS_x86_64_ICU_I18N:PATH=%source_root%\icu-%icu_version%\lib64\icuin.lib^ + -DSWIFT_BUILD_DYNAMIC_STDLIB:BOOL=YES^ + -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY:BOOL=YES^ + -DSWIFT_BUILD_STATIC_STDLIB:BOOL=NO^ + -DSWIFT_BUILD_STATIC_SDK_OVERLAY:BOOL=NO^ + -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ + -DSWIFT_BUILD_SOURCEKIT:BOOL=YES^ + -DSWIFT_ENABLE_SOURCEKIT_TESTS:BOOL=YES^ + -DSWIFT_INSTALL_COMPONENTS="autolink-driver;compiler;clang-resource-dir-symlink;stdlib;sdk-overlay;editor-integration;tools;sourcekit-inproc;swift-remote-mirror;swift-remote-mirror-headers"^ + -DSWIFT_PARALLEL_LINK_JOBS=8^ + -DPYTHON_EXECUTABLE:PATH=%PYTHON_HOME%\python.exe^ + -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ + -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -S "%source_root%\swift" %exitOnError% + +cmake --build "%build_root%\swift" %exitOnError% +cmake --build "%build_root%\swift" --target install %exitOnError% + +goto :eof +endlocal + + +:test_swift +:: Tests the Swift compiler and the Swift Standard Library +setlocal enableextensions enabledelayedexpansion + +cmake --build "%build_root%\swift" --target check-swift %exitOnError% + +goto :eof +endlocal + + +:build_lldb +:: Configures, builds, and installs LLDB +setlocal enableextensions enabledelayedexpansion + +cmake^ + -B "%build_root%\lldb"^ + -G Ninja^ + -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ + -DCMAKE_C_COMPILER=clang-cl^ + -DCMAKE_CXX_COMPILER=clang-cl^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ + -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ + -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ + -DSwift_DIR:PATH=%build_root%\swift\lib\cmake\swift^ + -DLLVM_ENABLE_ASSERTIONS:BOOL=YES^ + -DLLDB_USE_STATIC_BINDINGS:BOOL=YES^ + -DPYTHON_HOME:PATH=%PYTHON_HOME%^ + -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ + -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -DLLDB_DISABLE_PYTHON=YES^ + -DLLDB_INCLUDE_TESTS:BOOL=NO^ + -S "%source_root%\lldb" %exitOnError% + +cmake --build "%build_root%\lldb" %exitOnError% +cmake --build "%build_root%\lldb" --target install %exitOnError% + +goto :eof +endlocal + + +:build_libdispatch +:: Configures, builds, and installs Dispatch +setlocal enableextensions enabledelayedexpansion + +cmake^ + -B "%build_root%\swift-corelibs-libdispatch"^ + -G Ninja^ + -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ + -DCMAKE_C_COMPILER=clang-cl^ + -DCMAKE_CXX_COMPILER=clang-cl^ + -DCMAKE_Swift_COMPILER=swiftc^ + -DSwift_DIR:PATH=%build_root%\swift\lib\cmake\swift^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ + -DCMAKE_C_COMPILER_TARGET=x86_64-unknown-windows-msvc^ + -DCMAKE_CXX_COMPILER_TARGET=x86_64-unknown-windows-msvc^ + -DENABLE_SWIFT:BOOL=YES^ + -DENABLE_TESTING:BOOL=YES^ + -DCMAKE_C_FLAGS:STRING="${CMAKE_C_FLAGS} --target=x86_64-unknown-windows-msvc /GS- /Oy /Gw /Gy"^ + -DCMAKE_CXX_FLAGS:STRING="${CMAKE_CXX_FLAGS} --target=x86_64-unknown-windows-msvc /GS- /Oy /Gw /Gy"^ + -DCMAKE_EXE_LINKER_FLAGS:STRING="/INCREMENTAL:NO"^ + -DCMAKE_SHARED_LINKER_FLAGS:STRING="/INCREMENTAL:NO"^ + -DCMAKE_Swift_COMPILER_TARGET:STRING=x86_64-unknown-windows-msvc^ + -DCMAKE_Swift_FLAGS:STRING="-resource-dir \"%install_directory%\lib\swift\""^ + -DCMAKE_Swift_LINK_FLAGS:STRING="-resource-dir \"%install_directory%\lib\swift\""^ + -S "%source_root%\swift-corelibs-libdispatch" %exitOnError% + +cmake --build "%build_root%\swift-corelibs-libdispatch" %exitOnError% +cmake --build "%build_root%\swift-corelibs-libdispatch" --target install %exitOnError% + +goto :eof +endlocal + + +:test_libdispatch +:: Tests libdispatch C interface +setlocal enableextensions enabledelayedexpansion + +cmake --build "%build_root%\swift-corelibs-libdispatch" --target ExperimentalTest %exitOnError% + +goto :eof +endlocal + + +:end From ff36e32f8468bf2cc042f743eb948f2fb94a8e35 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Mon, 17 Aug 2020 12:07:55 -0700 Subject: [PATCH 186/663] Disable test decl-with-definition-irgen.swift --- test/Interop/Cxx/templates/decl-with-definition-irgen.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift index 34825a34ce7e4..d69ece5914b55 100644 --- a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift +++ b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift @@ -1,5 +1,5 @@ // RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s - +// REQUIRES: rdar67257133 import DeclWithDefinition public func getWrappedMagicInt() -> CInt { From fddfd6d782ca643aa9c9776680f4dfd7295beb4d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 13 Aug 2020 17:24:25 -0700 Subject: [PATCH 187/663] [BuilderTransform] Suppress diagnostics produced by `preCheckExpression` --- include/swift/AST/DiagnosticEngine.h | 6 ++++++ lib/Sema/BuilderTransform.cpp | 23 ++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index ee3c776cd9db6..d8dfa6575370f 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -1056,6 +1056,12 @@ namespace swift { } } + bool hasDiagnostics() const { + return std::distance(Engine.TentativeDiagnostics.begin() + + PrevDiagnostics, + Engine.TentativeDiagnostics.end()) > 0; + } + /// Abort and close this transaction and erase all diagnostics /// record while it was open. void abort() { diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 4c976d26a0f1d..d7d63dcd047f8 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1712,7 +1712,7 @@ class PreCheckFunctionBuilderApplication : public ASTWalker { public: PreCheckFunctionBuilderApplication(AnyFunctionRef fn, bool skipPrecheck) - : Fn(fn), SkipPrecheck(skipPrecheck) {} + : Fn(fn), SkipPrecheck(skipPrecheck) {} const std::vector getReturnStmts() const { return ReturnStmts; } @@ -1736,16 +1736,25 @@ class PreCheckFunctionBuilderApplication : public ASTWalker { } std::pair walkToExprPre(Expr *E) override { + if (SkipPrecheck) + return std::make_pair(false, E); + // Pre-check the expression. If this fails, abort the walk immediately. // Otherwise, replace the expression with the result of pre-checking. // In either case, don't recurse into the expression. - if (!SkipPrecheck && - ConstraintSystem::preCheckExpression(E, /*DC*/ Fn.getAsDeclContext())) { - HasError = true; - return std::make_pair(false, nullptr); - } + { + auto *DC = Fn.getAsDeclContext(); + auto &diagEngine = DC->getASTContext().Diags; - return std::make_pair(false, E); + // Suppress any diangostics which could be produced by this expression. + DiagnosticTransaction transaction(diagEngine); + + HasError |= ConstraintSystem::preCheckExpression(E, DC); + HasError |= transaction.hasDiagnostics(); + + transaction.abort(); + return std::make_pair(false, HasError ? nullptr : E); + } } std::pair walkToStmtPre(Stmt *S) override { From 3ad8ea86bbca9c430da9f664a6222ebd2ca65a56 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 14 Aug 2020 12:32:56 -0700 Subject: [PATCH 188/663] [CSFix] Add a fix to ignore function builder body which fails pre-check Fix is anchored on a `BraceStmt` associated with an invalid closure. It's diagnosing the problem by calling `ConstraintSystem::preCheckExpression` for all expressions in the body without suppressing errors. --- lib/Sema/CSFix.cpp | 37 +++++++++++++++++++++++++++++++++++++ lib/Sema/CSFix.h | 23 +++++++++++++++++++++++ lib/Sema/CSSimplify.cpp | 3 ++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 2718add47959c..c7a782c200f54 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1551,3 +1551,40 @@ AllowKeyPathWithoutComponents::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowKeyPathWithoutComponents(cs, locator); } + +bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, + bool asNote) const { + auto *S = getAnchor().get(); + + class PreCheckWalker : public ASTWalker { + DeclContext *DC; + + public: + PreCheckWalker(DeclContext *dc) : DC(dc) {} + + std::pair walkToExprPre(Expr *E) override { + auto hasError = ConstraintSystem::preCheckExpression(E, DC); + return std::make_pair(false, hasError ? nullptr : E); + } + + std::pair walkToStmtPre(Stmt *S) override { + return std::make_pair(true, S); + } + + // Ignore patterns because function builder pre-check does so as well. + std::pair walkToPatternPre(Pattern *P) override { + return std::make_pair(false, P); + } + }; + + PreCheckWalker walker(solution.getDC()); + S->walk(walker); + + return true; +} + +IgnoreInvalidFunctionBuilderBody * +IgnoreInvalidFunctionBuilderBody::create(ConstraintSystem &cs, + ConstraintLocator *locator) { + return new (cs.getAllocator()) IgnoreInvalidFunctionBuilderBody(cs, locator); +} diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index c834561b99262..7bcaf50f85c65 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -276,6 +276,9 @@ enum class FixKind : uint8_t { /// Allow key path expressions with no components. AllowKeyPathWithoutComponents, + + /// Ignore function builder body which fails `pre-check` call. + IgnoreInvalidFunctionBuilderBody, }; class ConstraintFix { @@ -1980,6 +1983,26 @@ class AllowKeyPathWithoutComponents final : public ConstraintFix { ConstraintLocator *locator); }; +class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix { + IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator) {} + +public: + std::string getName() const override { + return "ignore invalid function builder body"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + + static IgnoreInvalidFunctionBuilderBody *create(ConstraintSystem &cs, + ConstraintLocator *locator); +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 637e9757797fd..1608f19e49155 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -9997,7 +9997,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowCoercionToForceCast: case FixKind::SpecifyKeyPathRootType: case FixKind::SpecifyLabelToAssociateTrailingClosure: - case FixKind::AllowKeyPathWithoutComponents: { + case FixKind::AllowKeyPathWithoutComponents: + case FixKind::IgnoreInvalidFunctionBuilderBody: { return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; } From bc319779d577b6233cbba98329d13101af609c10 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 14 Aug 2020 14:21:41 -0700 Subject: [PATCH 189/663] [TypeChecker] Replace invalid refs with `ErrorExpr` only when explicitly allowed Add a flag to `ConstraintSystem::preCheckExpression` and subsequently to `TypeChecker::resolveDeclRefExpr` to indicate whether it's allowed to replace invalid member refs with `ErrorExpr`. It is useful for diagnostics and code completion to preserve AST in it's original state otherwise it's impossible to diagnose errors post factum or extract `CodeCompletionExpr` when it's a child of an invalid reference. --- lib/Sema/BuilderTransform.cpp | 3 +- lib/Sema/CSFix.cpp | 3 +- lib/Sema/CSSolver.cpp | 3 +- lib/Sema/ConstraintSystem.h | 8 ++++-- lib/Sema/TypeCheckCodeCompletion.cpp | 7 +++-- lib/Sema/TypeCheckConstraints.cpp | 42 ++++++++++++++++++++-------- lib/Sema/TypeCheckPattern.cpp | 5 ++-- lib/Sema/TypeChecker.h | 6 +++- 8 files changed, 54 insertions(+), 23 deletions(-) diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index d7d63dcd047f8..a0b8257689f4a 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1749,7 +1749,8 @@ class PreCheckFunctionBuilderApplication : public ASTWalker { // Suppress any diangostics which could be produced by this expression. DiagnosticTransaction transaction(diagEngine); - HasError |= ConstraintSystem::preCheckExpression(E, DC); + HasError |= ConstraintSystem::preCheckExpression( + E, DC, /*replaceInvalidRefsWithErrors=*/false); HasError |= transaction.hasDiagnostics(); transaction.abort(); diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index c7a782c200f54..992ea2552b52b 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1563,7 +1563,8 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, PreCheckWalker(DeclContext *dc) : DC(dc) {} std::pair walkToExprPre(Expr *E) override { - auto hasError = ConstraintSystem::preCheckExpression(E, DC); + auto hasError = ConstraintSystem::preCheckExpression( + E, DC, /*replaceInvalidRefsWithErrors=*/true); return std::make_pair(false, hasError ? nullptr : E); } diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 40e890e804525..8f0afc7b18b81 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1411,7 +1411,8 @@ void ConstraintSystem::solveForCodeCompletion( llvm::function_ref callback) { // First, pre-check the expression, validating any types that occur in the // expression and folding sequence expressions. - if (ConstraintSystem::preCheckExpression(expr, DC)) + if (ConstraintSystem::preCheckExpression( + expr, DC, /*replaceInvalidRefsWithErrors=*/true)) return; ConstraintSystemOptions options; diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 0e25261ada118..bc95ed45c0b55 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -4955,8 +4955,12 @@ class ConstraintSystem { public: /// Pre-check the expression, validating any types that occur in the /// expression and folding sequence expressions. - static bool preCheckExpression(Expr *&expr, DeclContext *dc); - + /// + /// \param replaceInvalidRefsWithErrors Indicates whether it's allowed + /// to replace any discovered invalid member references with `ErrorExpr`. + static bool preCheckExpression(Expr *&expr, DeclContext *dc, + bool replaceInvalidRefsWithErrors); + /// Solve the system of constraints generated from provided target. /// /// \param target The target that we'll generate constraints from, which diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index b40af172a2cd5..77a8222774652 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -553,10 +553,10 @@ TypeChecker::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS, // We allocate these expressions on the stack because we know they can't // escape and there isn't a better way to allocate scratch Expr nodes. UnresolvedDeclRefExpr UDRE(DeclNameRef(opName), refKind, DeclNameLoc(Loc)); - auto *opExpr = TypeChecker::resolveDeclRefExpr(&UDRE, DC); + auto *opExpr = TypeChecker::resolveDeclRefExpr( + &UDRE, DC, /*replaceInvalidRefsWithErrors=*/true); switch (refKind) { - case DeclRefKind::PostfixOperator: { // (postfix_unary_expr // (declref_expr name=) @@ -611,7 +611,8 @@ static Optional getTypeOfCompletionContextExpr( CompletionTypeCheckKind kind, Expr *&parsedExpr, ConcreteDeclRef &referencedDecl) { - if (constraints::ConstraintSystem::preCheckExpression(parsedExpr, DC)) + if (constraints::ConstraintSystem::preCheckExpression( + parsedExpr, DC, /*replaceInvalidRefsWithErrors=*/true)) return None; switch (kind) { diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index bcafe3d4d6bee..7eb6616d9a7d4 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -481,11 +481,18 @@ static bool findNonMembers(ArrayRef lookupResults, /// returning the resultant expression. Context is the DeclContext used /// for the lookup. Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, - DeclContext *DC) { + DeclContext *DC, + bool replaceInvalidRefsWithErrors) { // Process UnresolvedDeclRefExpr by doing an unqualified lookup. DeclNameRef Name = UDRE->getName(); SourceLoc Loc = UDRE->getLoc(); + auto errorResult = [&]() -> Expr * { + if (replaceInvalidRefsWithErrors) + return new (DC->getASTContext()) ErrorExpr(UDRE->getSourceRange()); + return UDRE; + }; + // Perform standard value name lookup. NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions; if (isa(DC)) @@ -506,7 +513,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, if (diagnoseRangeOperatorMisspell(Context.Diags, UDRE) || diagnoseIncDecOperator(Context.Diags, UDRE) || diagnoseOperatorJuxtaposition(UDRE, DC)) { - return new (Context) ErrorExpr(UDRE->getSourceRange()); + return errorResult(); } // Try ignoring access control. @@ -531,7 +538,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // Don't try to recover here; we'll get more access-related diagnostics // downstream if the type of the inaccessible decl is also inaccessible. - return new (Context) ErrorExpr(UDRE->getSourceRange()); + return errorResult(); } // TODO: Name will be a compound name if it was written explicitly as @@ -625,7 +632,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // TODO: consider recovering from here. We may want some way to suppress // downstream diagnostics, though. - return new (Context) ErrorExpr(UDRE->getSourceRange()); + return errorResult(); } // FIXME: Need to refactor the way we build an AST node from a lookup result! @@ -916,6 +923,10 @@ namespace { Expr *ParentExpr; + /// Indicates whether pre-check is allowed to insert + /// implicit `ErrorExpr` in place of invalid references. + bool UseErrorExprs; + /// A stack of expressions being walked, used to determine where to /// insert RebindSelfInConstructorExpr nodes. llvm::SmallVector ExprStack; @@ -1055,8 +1066,10 @@ namespace { } public: - PreCheckExpression(DeclContext *dc, Expr *parent) - : Ctx(dc->getASTContext()), DC(dc), ParentExpr(parent) {} + PreCheckExpression(DeclContext *dc, Expr *parent, + bool replaceInvalidRefsWithErrors) + : Ctx(dc->getASTContext()), DC(dc), ParentExpr(parent), + UseErrorExprs(replaceInvalidRefsWithErrors) {} ASTContext &getASTContext() const { return Ctx; } @@ -1122,7 +1135,8 @@ namespace { if (auto unresolved = dyn_cast(expr)) { TypeChecker::checkForForbiddenPrefix( getASTContext(), unresolved->getName().getBaseName()); - return finish(true, TypeChecker::resolveDeclRefExpr(unresolved, DC)); + return finish(true, TypeChecker::resolveDeclRefExpr(unresolved, DC, + UseErrorExprs)); } // Let's try to figure out if `InOutExpr` is out of place early @@ -1979,8 +1993,9 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) { /// Pre-check the expression, validating any types that occur in the /// expression and folding sequence expressions. -bool ConstraintSystem::preCheckExpression(Expr *&expr, DeclContext *dc) { - PreCheckExpression preCheck(dc, expr); +bool ConstraintSystem::preCheckExpression(Expr *&expr, DeclContext *dc, + bool replaceInvalidRefsWithErrors) { + PreCheckExpression preCheck(dc, expr, replaceInvalidRefsWithErrors); // Perform the pre-check. if (auto result = expr->walk(preCheck)) { expr = result; @@ -2107,7 +2122,8 @@ TypeChecker::typeCheckExpression( // First, pre-check the expression, validating any types that occur in the // expression and folding sequence expressions. - if (ConstraintSystem::preCheckExpression(expr, dc)) { + if (ConstraintSystem::preCheckExpression( + expr, dc, /*replaceInvalidRefsWithErrors=*/true)) { target.setExpr(expr); return None; } @@ -2336,13 +2352,15 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) { // Precheck the sequence. Expr *sequence = stmt->getSequence(); - if (ConstraintSystem::preCheckExpression(sequence, dc)) + if (ConstraintSystem::preCheckExpression( + sequence, dc, /*replaceInvalidRefsWithErrors=*/true)) return failed(); stmt->setSequence(sequence); // Precheck the filtering condition. if (Expr *whereExpr = stmt->getWhere()) { - if (ConstraintSystem::preCheckExpression(whereExpr, dc)) + if (ConstraintSystem::preCheckExpression( + whereExpr, dc, /*replaceInvalidRefsWithErrors=*/true)) return failed(); stmt->setWhere(whereExpr); diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 6a5ec66b76cb1..b02220919667d 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -530,9 +530,10 @@ class ResolvePattern : public ASTVisitor Date: Mon, 17 Aug 2020 10:16:45 -0700 Subject: [PATCH 190/663] [TypeChecker] Add a flag `PreCheckFunctionBuilderRequest` to suppress diagnostics --- include/swift/AST/TypeCheckRequests.h | 5 +++-- lib/Sema/BuilderTransform.cpp | 30 +++++++++++++++++++-------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 2f57ca2c6fd47..fc3572723cb6c 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1843,6 +1843,7 @@ class ValueWitnessRequest struct PreCheckFunctionBuilderDescriptor { AnyFunctionRef Fn; + bool SuppressDiagnostics; private: // NOTE: Since source tooling (e.g. code completion) might replace the body, @@ -1852,8 +1853,8 @@ struct PreCheckFunctionBuilderDescriptor { BraceStmt *Body; public: - PreCheckFunctionBuilderDescriptor(AnyFunctionRef Fn) - : Fn(Fn), Body(Fn.getBody()) {} + PreCheckFunctionBuilderDescriptor(AnyFunctionRef Fn, bool suppressDiagnostics) + : Fn(Fn), SuppressDiagnostics(suppressDiagnostics), Body(Fn.getBody()) {} friend llvm::hash_code hash_value(const PreCheckFunctionBuilderDescriptor &owner) { diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index a0b8257689f4a..c14cb8e257f63 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1485,9 +1485,11 @@ Optional TypeChecker::applyFunctionBuilderBodyTransform( // If we encountered an error or there was an explicit result type, // bail out and report that to the caller. auto &ctx = func->getASTContext(); - auto request = PreCheckFunctionBuilderRequest{AnyFunctionRef(func)}; - switch (evaluateOrDefault( - ctx.evaluator, request, FunctionBuilderBodyPreCheck::Error)) { + auto request = + PreCheckFunctionBuilderRequest{{AnyFunctionRef(func), + /*SuppressDiagnostics=*/false}}; + switch (evaluateOrDefault(ctx.evaluator, request, + FunctionBuilderBodyPreCheck::Error)) { case FunctionBuilderBodyPreCheck::Okay: // If the pre-check was okay, apply the function-builder transform. break; @@ -1619,7 +1621,8 @@ ConstraintSystem::matchFunctionBuilder( // Pre-check the body: pre-check any expressions in it and look // for return statements. - auto request = PreCheckFunctionBuilderRequest{fn}; + auto request = + PreCheckFunctionBuilderRequest{{fn, /*SuppressDiagnostics=*/false}}; switch (evaluateOrDefault(getASTContext().evaluator, request, FunctionBuilderBodyPreCheck::Error)) { case FunctionBuilderBodyPreCheck::Okay: @@ -1705,14 +1708,17 @@ namespace { class PreCheckFunctionBuilderApplication : public ASTWalker { AnyFunctionRef Fn; bool SkipPrecheck = false; + bool SuppressDiagnostics = false; std::vector ReturnStmts; bool HasError = false; bool hasReturnStmt() const { return !ReturnStmts.empty(); } public: - PreCheckFunctionBuilderApplication(AnyFunctionRef fn, bool skipPrecheck) - : Fn(fn), SkipPrecheck(skipPrecheck) {} + PreCheckFunctionBuilderApplication(AnyFunctionRef fn, bool skipPrecheck, + bool suppressDiagnostics) + : Fn(fn), SkipPrecheck(skipPrecheck), + SuppressDiagnostics(suppressDiagnostics) {} const std::vector getReturnStmts() const { return ReturnStmts; } @@ -1753,7 +1759,9 @@ class PreCheckFunctionBuilderApplication : public ASTWalker { E, DC, /*replaceInvalidRefsWithErrors=*/false); HasError |= transaction.hasDiagnostics(); - transaction.abort(); + if (SuppressDiagnostics) + transaction.abort(); + return std::make_pair(false, HasError ? nullptr : E); } } @@ -1788,11 +1796,15 @@ FunctionBuilderBodyPreCheck PreCheckFunctionBuilderRequest::evaluate( owner.Fn.getAbstractClosureExpr())) skipPrecheck = shouldTypeCheckInEnclosingExpression(closure); - return PreCheckFunctionBuilderApplication(owner.Fn, false).run(); + return PreCheckFunctionBuilderApplication( + owner.Fn, /*skipPrecheck=*/false, + /*suppressDiagnostics=*/owner.SuppressDiagnostics) + .run(); } std::vector TypeChecker::findReturnStatements(AnyFunctionRef fn) { - PreCheckFunctionBuilderApplication precheck(fn, true); + PreCheckFunctionBuilderApplication precheck(fn, /*skipPreCheck=*/true, + /*SuppressDiagnostics=*/true); (void)precheck.run(); return precheck.getReturnStmts(); } From da6bb3657f5fb2ac2d2fab358d9d665ee4acfe61 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 17 Aug 2020 10:54:02 -0700 Subject: [PATCH 191/663] [CSFix] Adjust `IgnoreInvalidFunctionBuilderBody` to return `true` only if errors are emitted --- lib/Sema/CSFix.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 992ea2552b52b..80cc9fc225ad6 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1558,9 +1558,11 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, class PreCheckWalker : public ASTWalker { DeclContext *DC; + DiagnosticTransaction Transaction; public: - PreCheckWalker(DeclContext *dc) : DC(dc) {} + PreCheckWalker(DeclContext *dc) + : DC(dc), Transaction(dc->getASTContext().Diags) {} std::pair walkToExprPre(Expr *E) override { auto hasError = ConstraintSystem::preCheckExpression( @@ -1576,12 +1578,16 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, std::pair walkToPatternPre(Pattern *P) override { return std::make_pair(false, P); } + + bool diagnosed() const { + return Transaction.hasDiagnostics(); + } }; PreCheckWalker walker(solution.getDC()); S->walk(walker); - return true; + return walker.diagnosed(); } IgnoreInvalidFunctionBuilderBody * From 56ef379fb833ae709d1bb6bb222a4aa3123c3ac9 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 17 Aug 2020 11:04:57 -0700 Subject: [PATCH 192/663] [ConstraintSystem] Integrate `IgnoreInvalidFunctionBuilderBody` into the solver --- lib/Sema/BuilderTransform.cpp | 15 +++++-- lib/Sema/CSBindings.cpp | 9 +++- test/Constraints/function_builder_diags.swift | 13 +++--- test/Constraints/rdar65320500.swift | 43 +++++++++++++++++++ 4 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 test/Constraints/rdar65320500.swift diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index c14cb8e257f63..655ee51fdcd12 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1622,16 +1622,23 @@ ConstraintSystem::matchFunctionBuilder( // Pre-check the body: pre-check any expressions in it and look // for return statements. auto request = - PreCheckFunctionBuilderRequest{{fn, /*SuppressDiagnostics=*/false}}; + PreCheckFunctionBuilderRequest{{fn, /*SuppressDiagnostics=*/true}}; switch (evaluateOrDefault(getASTContext().evaluator, request, FunctionBuilderBodyPreCheck::Error)) { case FunctionBuilderBodyPreCheck::Okay: // If the pre-check was okay, apply the function-builder transform. break; - case FunctionBuilderBodyPreCheck::Error: - // If the pre-check had an error, flag that. - return getTypeMatchFailure(locator); + case FunctionBuilderBodyPreCheck::Error: { + if (!shouldAttemptFixes()) + return getTypeMatchFailure(locator); + + if (recordFix(IgnoreInvalidFunctionBuilderBody::create( + *this, getConstraintLocator(fn.getBody())))) + return getTypeMatchFailure(locator); + + return getTypeMatchSuccess(); + } case FunctionBuilderBodyPreCheck::HasReturnStmt: // If the body has a return statement, suppress the transform but diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 7e7f3a3ffde8f..8919c9e352f4f 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -1206,7 +1206,14 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const { } else if (TypeVar->getImpl().isClosureParameterType()) { fix = SpecifyClosureParameterType::create(cs, dstLocator); } else if (TypeVar->getImpl().isClosureResultType()) { - fix = SpecifyClosureReturnType::create(cs, dstLocator); + auto *locator = TypeVar->getImpl().getLocator(); + auto *closure = castToExpr(locator->getAnchor()); + // If the whole body is being ignored due to a pre-check failure, + // let's not record a fix about result type since there is + // just not enough context to infer it without a body. + if (!cs.hasFixFor(cs.getConstraintLocator(closure->getBody()), + FixKind::IgnoreInvalidFunctionBuilderBody)) + fix = SpecifyClosureReturnType::create(cs, dstLocator); } else if (srcLocator->directlyAt()) { fix = SpecifyObjectLiteralTypeImport::create(cs, dstLocator); } else if (srcLocator->isKeyPathRoot()) { diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 7a7029b499935..8147e248999d8 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -6,7 +6,7 @@ enum Either { } @_functionBuilder -struct TupleBuilder { // expected-note 3{{struct 'TupleBuilder' declared here}} +struct TupleBuilder { // expected-note 2 {{struct 'TupleBuilder' declared here}} static func buildBlock() -> () { } static func buildBlock(_ t1: T1) -> T1 { @@ -87,7 +87,7 @@ func testDiags() { // For loop tuplify(true) { _ in 17 - for c in name { // expected-error{{closure containing control flow statement cannot be used with function builder 'TupleBuilder'}} + for c in name { // expected-error@-1 {{cannot find 'name' in scope}} } } @@ -418,13 +418,16 @@ func testNonExhaustiveSwitch(e: E) { // rdar://problem/59856491 struct TestConstraintGenerationErrors { @TupleBuilder var buildTupleFnBody: String { - let a = nil // expected-error {{'nil' requires a contextual type}} + let a = nil // There is no diagnostic here because next line fails to pre-check, so body is invalid String(nothing) // expected-error {{cannot find 'nothing' in scope}} } + @TupleBuilder var nilWithoutContext: String { + let a = nil // expected-error {{'nil' requires a contextual type}} + } + func buildTupleClosure() { - // FIXME: suppress the ambiguity error - tuplify(true) { _ in // expected-error {{type of expression is ambiguous without more context}} + tuplify(true) { _ in let a = nothing // expected-error {{cannot find 'nothing' in scope}} String(nothing) // expected-error {{cannot find 'nothing' in scope}} } diff --git a/test/Constraints/rdar65320500.swift b/test/Constraints/rdar65320500.swift new file mode 100644 index 0000000000000..dfb8f722a2692 --- /dev/null +++ b/test/Constraints/rdar65320500.swift @@ -0,0 +1,43 @@ +// RUN: %target-typecheck-verify-swift + +struct Result {} + +@_functionBuilder +struct Builder { + static func buildBlock() -> Result { + Result() + } +} + +func test_builder(@Builder _: () -> T) {} +func test_builder(@Builder _: () -> Int) {} + +test_builder { + let _ = 0 + + if let x = does_not_exist { // expected-error {{cannot find 'does_not_exist' in scope}} + } +} + +func test(_: Int) -> Bool { + return false +} + +test_builder { + let totalSeconds = 42000 + test(totalseconds / 3600) // expected-error {{cannot find 'totalseconds' in scope}} +} + +test_builder { + test(doesntExist()) // expected-error {{cannot find 'doesntExist' in scope}} + + if let result = doesntExist() { // expected-error {{cannot find 'doesntExist' in scope}} + } + + if bar = test(42) {} // expected-error {{cannot find 'bar' in scope}} + + let foo = bar() // expected-error {{cannot find 'bar' in scope}} + + switch (doesntExist()) { // expected-error {{cannot find 'doesntExist' in scope}} + } +} From 4c684d7a76a0cdbc883cfe0b81fd91bd2327a3a7 Mon Sep 17 00:00:00 2001 From: tbkka Date: Mon, 17 Aug 2020 13:37:57 -0700 Subject: [PATCH 193/663] DynamicCast Rework, Part 1: Specification (#33010) A specification for Swift's dynamic casting operations. This specification tries to reflect the _intent_ of the current implementation, defining a consistent behavior that reflects as far as possible the behavior of the current implementation. Deviations from this specification will generally be treated as bugs in the current implementation. --- docs/DynamicCasting.md | 687 +++++++++++++++++++++++++++++++++++++++++ docs/README.md | 2 + 2 files changed, 689 insertions(+) create mode 100644 docs/DynamicCasting.md diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md new file mode 100644 index 0000000000000..add2524d59e33 --- /dev/null +++ b/docs/DynamicCasting.md @@ -0,0 +1,687 @@ +# Dynamic Casting Behavior + +* Author: [Tim Kientzle](https://github.com/tbkka) +* Implementation: [apple/swift#29658](https://github.com/apple/swift/pull/29658) + +## Introduction + +The Swift language has three casting operators: `is`, `as?`, and `as!`. +Each one takes an instance on the left-hand side and a type expression on the right-hand side. + +* The _cast test operator_ `is` tests whether a particular instance can be converted to a particular destination type. It returns a boolean result. + +* The _conditional cast operator_ `as?` attempts the conversion and returns an `Optional` result: `nil` if the conversion failed, and a non-nil optional containing the result otherwise. + +* The _forced cast operator_ `as!` unconditionally performs the casting conversion and returns the result. If an `as!` expression does not succeed, the implementation may terminate the program. + +Note: The static coercion operator `as` serves a different role and its behavior will not be specifically discussed in this document. + +The following invariants relate the three casting operators: +* Cast test: `x is T == ((x as? T) != nil)` +* Conditional cast: `(x as? T) == (x is T) ? .some(x as! T) : nil` +* Forced cast: `x as! T` is equivalent to `(x as? T)!` + +In particular, note that `is` and `as!` can be implemented in terms of `as?` and vice-versa. + +As with other operators with `!` in their names, `as!` is intended to only be invoked in cases where the programmer knows a priori that the cast will succeed. +If the conversion would not succeed, then the behavior may not be fully deterministic. +See the discussion of Array casting below for a specific case where this non-determinism can be important. + +The following sections detail the rules that govern the casting operations for particular Swift types. +Except where noted, casting between types described in different sections below will always fail -- for example, casting a struct instance to a function type or vice-versa. + +Where possible, each section includes machine-verifiable _invariants_ that can be used as the basis for developing a robust test suite for this functionality. + +## Identity Cast + +Casting an instance of a type to its own type will always succeed and return the original value unchanged. + +``` +let a: Int = 7 +a is Int // true +a as? Int // Succeeds +a as! Int == a // true +``` + +## Classes + +Casting among class types follows standard object-oriented programming conventions: + +* Class upcasts: If `C` is a subclass of `SuperC` and `c` is an instance of `C`, then `c is SuperC == true` and `(c as? SuperC) != nil`. (Note: These "upcasts" do not change the in-memory representation.) However, when `c` is accessed via a variable or expression of type `SuperC`, only methods and instance variables defined on `SuperC` are available. + +* Class downcasts: If `C` is a subclass of `SuperC` and `sc` is an instance of `SuperC`, then `sc is C` will be true iff `sc` is actually an instance of `C`. (Note: Again, a downcast does not affect the in-memory representation.) + +* Objective-C class casting: The rules above also apply when one of the classes in question is defined with the `@objc` attribute or inherits from an Objective-C class. + +* Class casts to AnyObject: Any class reference can be cast to `AnyObject` and then cast back to the original type. See "AnyObject" below. + +* If a struct or enum type conforms to `_ObjectiveCBridgeable`, then classes of the associated bridging type can be cast to the struct or enum type and vice versa. See "The `_ObjectiveCBridgeable` Protocol" below. + +Invariants: +* For any two class types `C1` and `C2`: `c is C1 && c is C2` iff `((c as? C1) as? C2) != nil` +* For any class type `C`: `c is C` iff `(c as! AnyObject) is C` +* For any class type `C`: if `c is C`, then `(c as! AnyObject) as! C === c` + +## Structs and Enums + +You cannot cast between different concrete struct or enum types. +More formally: + +* If `S` and `T` are struct or enum types and `s is S == true`, then `s is T` iff `S.self == T.self`. + +## Tuples + +Casting from a tuple type T1 to a tuple type T2 will succeed iff the following hold: +* T1 and T2 have the same number of elements +* If an element has a label in both T1 and T2, the labels are identical +* Each element of T1 can be individually cast to the corresponding type of T2 + +## Functions + +Casting from a function type F1 to a function type F2 will succeed iff the following hold: +* The two types have the same number of arguments +* Corresponding arguments have identical types +* The return types are identical +* If F1 is a throwing function type, then F2 must be a throwing function type. If F1 is not throwing, then F2 may be a throwing or non-throwing function type. + +Note that it is _not_ sufficient for argument and return types to be castable; they must actually be identical. + +## Optionals + +Casting to and from optional types will transparently unwrap optionals as much as necessary, including nested optional types. + +* If `T` and `U` are any two types, and `t` is an instance of `T`, then `.some(t) is Optional == t is U` +* Optional injection: if `T` and `U` are any two types, `t` is a non-nil instance of `T`, then `t is Optional == t is U` +* Optional projection: if `T` and `U` are any two types, and `t` is an instance of `T`, then `.some(t) is U == t is U` +* Nil Casting: if `T` and `U` are any two types, then `Optional.none is Optional == true` + +Note: For "Optional Injection" above, the requirement that `t` is a non-nil instance of `T` implies that either `T` is not an `Optional` or that `T` is `Optional` and `t` has the form `.some(u)` + +Examples +``` +// T and U are any two distinct types (possibly optional) +// NO is any non-optional type +let t: T +let u: U +let no: NO +// Casting freely adds/removes optional wrappers +t is Optional == true +t is Optional> == true +Optional.some(t) is T == true +Optional>.some(.some(t)) is T == true +// Non-optionals cast to optionals iff they cast to the inner type +no is Optional == no is U +Optional.some(no) is Optional == no is U +// Non-nil optionals cast to a different type iff the inner value does +Optional.some(t) is U == t is U +Optional>.some(.some(t)) is U == t is U +// Nil optionals always cast to other optional types +Optional.none is Optional == true +// Nil optionals never cast to non-optionals +Optional.none is NO == false +``` + +Depth Preservation: +The rules above imply that nested optionals are transparently unwrapped to arbitrary depth. +For example, if an instance of `T` can be cast to type `U`, then `T????` can be cast to `U????`. +This can be ambiguous if the former contains a `nil` value; +casting the nil to `U????` might end up with any of the following distinct values `.none`, `.some(.none)`, `.some(.some(.none))`, or `.some(.some(.some(.none)))`. + +To resolve this ambiguity, the implementation should first inspect the type of the inner `.none` value and count the optional depth. +Note that "optional depth" here refers to the number of optional wrappers needed to get from the innermost non-optional type to the type of the `.none`. + +1. If the target allows it, the value should inject into the target with the same optional depth as the source. +2. Otherwise, the value should inject with the greatest optional depth possible. + +Examples +``` +// Depth preservation +// The `.none` here has type `T?` with optional depth 1 +let t1: T???? = .some(.some(.some(.none))) +// This `.none` has type `T????` with optional depth 4 +let t4: T???? = .none +// Result has optional depth 1, matching source +t1 as! U???? // Produces .some(.some(.some(.none))) +t1 as! U??? // Produces .some(.some(.none)) +t1 as! U?? // Produces .some(.none) +t1 as! U? // Produces .none +// Result has optional depth 2, because 4 is not possible +t4 as! U?? // Produces .none +// Remember that `as?` adds a layer of optional +// These casts succeed, hence the outer `.some` +t1 as? U???? // Produces .some(.some(.some(.some(.none)))) +t1 as? U??? // Produces .some(.some(.some(.none))) +t1 as? U?? // Produces .some(.some(.none)) +t1 as? U? // Produces .some(.none) +t4 as? U?? // Produces .some(.none) +``` + +## Any + +Any Swift instance can be cast to the type `Any`. +An instance of `Any` has no useful methods or properties; to utilize the contents, you must cast it to another type. +Every type identifier is an instance of the metatype `Any.Type`. + +Invariants +* If `t` is any instance, then `t is Any == true` +* If `t` is any instance, `t as! Any` always succeeds +* For every type `T` (including protocol types), `T.self is Any.Type` +* If `t` is any instance and `U` is any `Equatable` type, then `t as? U == (t as! Any) as? U`. + +This last invariant deserves some explanation, as a similar pattern appears repeatedly throughout this document. +In essence, this invariant just says that putting something into an "Any box" (`t as! Any`) and taking it out again (`as? U`) does not change the result. +The requirement that `U` be `Equatable` is a technical necessity for using `==` in this statement. + +Note that in many cases, we've shortened such invariants to the form `t is U == (t as! Any) is U`. +Using `is` here simply avoids the technical necessity that `U` be `Equatable` but except where explicitly called out, the intention in every case is that such casting does not change the value. + +## AnyObject + +Any class, enum, struct, tuple, function, metatype, or existential metatype instance can be cast to `AnyObject`. + +XXX TODO The runtime logic has code to cast protocol types to `AnyObject` only if they are compatible with `__SwiftValue`. What is the practical effect of this logic? Does it mean that casting a protocol type to `AnyObject` will sometimes unwrap (if the protocol is incompatible) and sometimes not? What protocols are affected by this? + +The contents of an `AnyObject` container can be accessed by casting to another type: +* If `t` is any instance, `U` is any type, `t is AnyObject` and `t is U`, then `(t as! AnyObject) is U`. + +Implementation Note: `AnyObject` is represented in memory as a pointer to a refcounted object. The dynamic type of the object can be recovered from the "isa" field of the object. The optional form `AnyObject?` is the same except that it allows null. Reference types (class, metatype, or existential metatype instances) can be directly assigned to an `AnyObject` without any conversion. For non-reference types -- including struct, enum, and tuple types -- the casting logic will first look for an `_ObjectiveCBridgeable` conformance that it can use to convert the source into a tailored reference type. If that fails, the value will be copied into an opaque `_SwiftValue` container. + +(See "The _ObjectiveCBridgeable Protocol" below for more details.) + +### Objective-C Interactions + +Note the invariant above cannot be an equality because Objective-C bridging allows libraries to introduce new relationships that can alter the behavior of seemingly-unrelated casts. +One example of this is Foundation's `Number` (or `NSNumber`) type which conditionally bridges to several Swift numeric types. +As a result, when Foundation is in scope, `Int(7) is Double == false` but `(Int(7) as! AnyObject) is Double == true`. +In general, the ability to add new bridging behaviors from a single type to several distinct types implies that Swift casting cannot be transitive. + +## Error (SE-0112) + +Although the Error protocol is specially handled by the Swift compiler and runtime (as detailed in [SE-0112](https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md)), it behaves like an ordinary protocol type for casting purposes. + +(See "Note: 'Self-conforming' protocols" below for additional details relevant to the Error protocol.) + +## AnyHashable (SE-0131) + +For casting purposes, `AnyHashable` behaves like a protocol type. + +## Existential/Protocol types + +Caveat: +Protocols that have `associatedtype` properties or which make use of the `Self` typealias cannot be used as independent types. +As such, the discussion below does not apply to them. + +Any Swift instance of a concrete type `T` can be cast to `P` iff `T` conforms to `P`. +The result is a "protocol witness" instance that provides access only to those methods and properties defined on `P`. +Other capabilities of the type `T` are not accessible from a `P` instance. + +The contents of a protocol witness can be accessed by casting to some other appropriate type: +* For any protocol `P`, instance `t`, and type `U`, if `t is P`, then `t as? U == (t as! P) as? U` + +XXX TODO: The invariant above does not apply to AnyObject, AnyHashable. +Does it suffice to explicitly exclude those two, or do other protocols share that behavior? The alternative would seem to be to change the equality here into an implication. + +In addition to the protocol witness type, every Swift protocol `P` implicitly defines two other types: +`P.Protocol` is the "protocol metatype", the type of `P.self`. +`P.Type` is the "protocol existential metatype". +These are described in more detail below. + +Regarding Protocol casts and Optionals + +When casting an Optional to a protocol type, the optional is preserved if possible. +Given an instance `o` of type `Optional` and a protocol `P`, the cast request `o as? P` will produce different results depending on whether `Optional` directly conforms to `P`: + +* If `Optional` conforms to `P`, then the result will be a protocol witness wrapping the `o` instance. In this case, a subsequent cast to `Optional` will restore the original instance. In particular, this case will preserve `nil` instances. + +* If `Optional` does not directly conform, then `o` will be unwrapped and the cast will be attempted with the contained object. If `o == nil`, this will fail. In the case of a nested optional `T???` this will result in fully unwrapping the inner non-optional. + +* If all of the above fail, then the cast will fail. + +For example, `Optional` conforms to `CustomDebugStringConvertible` but not to `CustomStringConvertible`. +Casting an optional instance to the first of these protocols will result in an item whose `.debugDescription` will describe the optional instance. +Casting an optional instance to the second will provide an instance whose `.description` property describes the inner non-Optional instance. + +## Array/Set/Dictionary Casts + +For Array, Set, or Dictionary types, you can use the casting operators to translate to another instance of the same outer container (Array, Set, or Dictionary respectively) with a different component type. +Note that the following discussion applies only to these specific types. +It does not apply to any other types, nor is there any mechanism to add this behavior to other types. + +Example: Given an `arr` of type `Array`, you can cast `arr as? Array`. +The result will be a new array where each `Int` in the original array has been individually cast to an `Any`. + +However, if any component item cannot be cast, then the outer cast will also fail. +For example, consider the following: +``` +let a: Array = [Int(7), "string"] +a as? Array // Fails because "string" cannot be cast to `Int` +``` + +Specifically, the casting operator acts for `Array` as if it were implemented as follows. +In particular, note that an empty array can be successfully cast to any destination array type. +``` +func arrayCast(source: Array) -> Optional> { + var result = Array() + for t in source { + if let u = t as? U { + result.append(u) + } else { + return nil + } + } + return result +} +``` + +Invariants +* Arrays cast iff their contents do: If `t` is an instance of `T` and `U` is any type, then `t is U == [t] is [U]` +* Empty arrays always cast: If `T` and `U` are any types, `Array() is Array` + +Similar logic applies to `Set` and `Dictionary` casts. +Note that the resulting `Set` or `Dictionary` may have fewer items than the original if the component casting operation converts non-equal items in the source into equal items in the destination. + +Specifically, the casting operator acts on `Set` and `Dictionary` as if by the following code: +``` +func setCast(source: Set) -> Optional> { + var result = Set() + for t in source { + if let u = t as? U { + result.append(u) + } else { + return nil + } + } + return result +} + +func dictionaryCast(source: Dictionary) -> Optional> { + var result = Dictionary() + for (k,v) in source { + if let k2 = k as? K2, v2 = v as? V2 { + result[k2] = v2 + } else { + return nil + } + } + return result +} +``` + +### Collection Casting performance and `as!` + +For `as?` casts, the casting behavior above requires that every element be converted separately. +This can be a particular bottleneck when trying to share large containers between Swift and Objective-C code. + +However, for `as!` casts, it is the programmer's responsibility to guarantee that the operation will succeed before requesting the conversion. +The implementation is allowed (but not required) to exploit this by deferring the inner component casts until the relevant item is needed. +Such lazy conversion can provide a significant performance improvement in cases where the data is known (by the programmer) to be safe and where the inner component casts are non-trivial. +However, if the conversion cannot be completed, it is indeterminate whether the cast request will fail immediately or whether the program will fail at some later point. + +## Metatypes + +For every type `T`, there is a unique instance `T.self` that represents the type at runtime. +As with all instances, `T.self` has a type. +We call this type the "metatype of `T`". +Technically, static variables or methods of a type belong to the `T.self` instance and are defined by the metatype of `T`: + +Example: +``` +struct S { + let ivar = 2 + static let svar = 1 +} +S.ivar // Error: only available on an instance +S().ivar // 2 +type(of: S()) == S.self +S.self.svar // 1 +S.svar // Shorthand for S.self.svar +``` + +For most Swift types, the metatype of `T` is named `T.Type`. +However, in two cases the metatype has a different name: +* For a nominal protocol type `P`, the metatype is named `P.Protocol` +* For a type bound to a generic variable `G`, the metatype is named `G.Type` _even if `G` is bound to a protocol type_. Specifically, if `G` is bound to the nominal protocol type `P`, then `G.Type` is another name for the metatype `P.Protocol`, and hence `G.Type.self == P.Protocol.self`. + +Example: +``` +// Metatype of a struct type +struct S: P {} +S.self is S.Type // always true +S.Type.self is S.Type.Type // always true +let s = S() +type(of: s) == S.self // always true +type(of: S.self) == S.Type.self + +// Metatype of a protocol type +protocol P {} +P.self is P.Protocol // always true +// P.Protocol is a metatype, not a protocol, so: +P.Protocol.self is P.Protocol.Type // always true +let p = s as! P +type(of: p) == P.self // always true + +// Metatype for a type bound to a generic type variable +f(s) // Bind G to S +f(p) // Bind G to P +func f(_ g: G) { + G.self is G.Type // always true +} +``` + +Invariants +* For a nominal non-protocol type `T`, `T.self is T.Type` +* For a nominal protocol type `P`, `P.self is P.Protocol` +* `P.Protocol` is a singleton: `T.self is P.Protocol` iff `T` is exactly `P` +* A non-protocol type `T` conforms to a protocol `P` iff `T.self is P.Type` +* `T` is a subtype of a non-protocol type `U` iff `T.self is U.Type` +* Subtypes define metatype subtypes: if `T` and `U` are non-protocol types, `T.self is U.Type == T.Type.self is U.Type.Type` +* Subtypes define metatype subtypes: if `T` is a non-protocol type and `P` is a protocol type, `T.self is P.Protocol == T.Type.self is P.Protocol.Type` + +## Existential Metatypes + +Protocols can specify constraints and provide default implementations for instances of types. +They can also specify constraints and provide default implementations for static members of types. +As described above, casting a regular instance of a type to a protocol type produces a protocol witness instance that exposes only those features required or provided by the protocol. +Similarly, a type identifier instance (`T.self`) can be cast to a protocol's "existential metatype" to expose just the parts of the type corresponding to the protocol's static requirements. + +The existential metatype of a protocol `P` is called `P.Type`. +(Recall that for a non-protocol type `T`, the expression `T.Type` refers to the regular metatype. +Non-protocol types do not have existential metatypes. +For a generic variable `G`, the expression also refers to the regular metatype, even if the generic variable is bound to a protocol. +There is no mechanism in Swift to refer to the existential metatype via a generic variable.) + +Example +``` +protocol P { + var ivar: Int { get } + static svar: Int { get } +} +struct S: P { + let ivar = 1 + static let svar = 2 +} +S().ivar // 1 +S.self.svar // 2 +(S() as! P).ivar // 1 +(S.self as! P.Type).svar // 2 +``` + +Invariants +* If `T` conforms to `P` and `t` is an instance of `T`, then `t is P`, and `T.self is P.Type` +* Since every type `T` conforms to `Any`, `T.self is Any.Type` is always true +* `Any` self-conforms: `Any.self is Any.Type == true` + +### Note: "Self conforming" protocols + +As mentioned above, a protocol definition for `P` implicitly defines types `P.Type` (the existential metatype) and `P.Protocol` (the metatype). +It also defines an associated type called `P` which is the type of a container that can hold any object whose concrete type conforms to the protocol `P`. + +A protocol is "self conforming" if the container type `P` conforms to the protocol `P`. +This is equivalent to saying that `P.self` is an instance of `P.Type`. +(Remember that `P.self` is always an instance of `P.Protocol`.) + +This is a concern for Swift because of the following construct, which attempts to invoke a generic `f` in a situation where the concrete instance clearly conforms to `P` but is represented as a `P` existential: +``` +func f(t: T) { .. use t .. } +let a : P = something +f(a) +``` +This construct is valid only if `T` conforms to `P` when `T = P`; that is, if `P` self-conforms. + +A similar situation arises with generic types: +``` +struct MyGenericType { + init(_ value: T) { ... } +} +let a : P +let b : MyGenericType(a) +``` +As above, since `a` has type `P`, this code is instantiating `MyGenericType` with `T = P`, which is only valid if `P` conforms to `P`. + +Note that any protocol that specifies static methods, static properties, associated types, or initializers cannot possibly be self-conforming. +As of Swift 5.3, there are only three kinds of self-conforming protocols: +* `Any` must be self-conforming since every `T.self` is an instance of `Any.Type` +* `Error` is a self-conforming protocol +* Objective-C protocols that have no static requirements are self-conforming + +## CoreFoundation types + +* If `CF` is a CoreFoundation type, `cf` is an instance of `CF`, and `NS` is the corresponding Objective-C type, then `cf is NS == true` +* Further, since every Objective-C type inherits from `NSObject`, `cf is NSObject == true` +* In the above situation, if `T` is some other type and `cf is NS == true`, then `cf as! NS is T` iff `cf is T`. + +The intention of the above is to treat instances of CoreFoundation types as being simultaneously instances of the corresponding Objective-C type, in keeping with the general dual nature of these types. +In particular, if a protocol conformance is declared on the Objective-C type, then instances of the CoreFoundation type can be cast to the protocol type directly. + +XXX TODO: Converse? If ObjC instance has CF equivalent and CF type is extended, ... ?? + +## Objective-C types + +The following discussion applies in three different cases: +* _Explicit_ conversions from use of the `is`, `as?`, and `as!` operators. +* _Implicit_ conversions from Swift to Objective-C: These conversions are generated automatically when Swift code calls an Objective-C function or method with an argument that is not already of an Objective-C type, or when a Swift function returns a value to an Objective-C caller. +* _Implicit_ conversions from Objective-C to Swift: These are generated automatically when arguments are passed from an Objective-C caller to a Swift function, or when an Objective-C function returns a value to a Swift caller. +Unless stated otherwise, all of the following cases apply equally to all three of the above cases. + +Explicit casts among Swift and Objective-C class types follow the same general rules described earlier for class types in general. +Likewise, explicitly casting a class instance to an Objective-C protocol type follows the general rules for casts to protocol types. + +XXX TODO EXPLAIN Implicit conversions from Objective-C types to Swift types XXXX. + +CoreFoundation types can be explicitly cast to and from their corresponding Objective-C types as described above. + +Objective-C types and protocols +* `T` is an Objective-C class type iff `T.self is NSObject.Type` +* `P` is an Objective-C protocol iff XXX TODO XXX + +## The `_ObjectiveCBridgeable` Protocol + +The `_ObjectiveCBridgeable` protocol allows certain types to opt into custom casting behavior. +Note that although this mechanism was explicitly designed to simplify Swift interoperability with Objective-C, it is not necessarily tied to Objective-C. + +The `_ObjectiveCBridgeable` protocol defines an associated reference type `_ObjectiveCType`, along with a collection of methods that support casting to and from the associated `_ObjectiveCType`. +This protocol allows library code to provide tailored mechanisms for casting Swift types to reference types. +When casting to `AnyObject`, the casting logic prefers this tailored mechanism to the general `_SwiftValue` container mentioned above. + +Note: The associated `_ObjectiveCType` is constrained to be a subtype of `AnyObject`; it is not limited to being an actual Objective-C type. +In particular, this mechanism is equally available to the Swift implementation of Foundation on non-Apple platforms and the Objective-C Foundation on Apple platforms. + +Example #1: Foundation extends the `Array` type in the standard library with an `_ObjectiveCBridgeable` conformance to `NSArray`. This allows Swift arrays to be cast to and from Foundation `NSArray` instances. +``` +let a = [1, 2, 3] // Array +let b = a as? AnyObject // casts to NSArray +``` + +Example #2: Foundation also extends each Swift numeric type with an `_ObjectiveCBridgeable` conformance to `NSNumber`. +``` +let a = 1 // Int +// After the next line, b is an Optional +// holding a reference to an NSNumber +let b = a as? AnyObject +// NSNumber is bridgeable to Double +let c = b as? Double +``` + +## Implementation Notes + +Casting operators that appear in source code are translated into SIL in a variety of ways depending on the details of the types involved. +One common path renders `as!` into some variant of the `unconditional_checked_cast` instruction and renders `as?` and `is` into a conditional branch instruction such as `checked_cast_br`. + +SIL optimization passes attempt to simplify these. +In some cases, the result of the cast can be fully determined at compile time. +In a few cases, the compiler can generate tailored code to perform the cast (for example, assigning a reference to an `AnyObject` variable). +In other cases, the compiler can determine whether the cast will succeed without necessarily being able to compute the result. +For example, casting a class reference to a superclass will always succeed, which may allow a `checked_cast_br` instruction to be simplified into a non-branching `unconditional_checked_cast`. +Similarly, an `as?` cast that can be statically proven to always fail can be simplified into a constant `nil` value. +Note that these SIL functions are also used for other purposes, including implicit bridging conversions when calling into Objective-C. +This makes them common enough to be subject to some limited optimizations even in `-Onone` mode. + +When SIL is translated into LLVM IR, the remaining cast operations are rendered into calls to appropriate runtime functions. +The most general such function is `swift_dynamicCast` which accepts a pointer to the input value, a location in which to store the result, and metadata describing the types involved. +When possible, the compiler prefers to instead emit calls to specialized variants of this function with names like `swift_dynamicCastClass` and `swift_dynamicCastMetatypeToObject` (a full list is in the [Runtime Documentation](/docs/Runtime.md)). +These specialized versions require fewer arguments and perform fewer internal checks, which makes them cheaper to use. + +The `swift_dynamicCast` function examines the input and output types to determine appropriate conversions. +This process recurses on the input type to examine the contents of an existential container or `Optional`. +If the output is an existential container or `Optional` type, it will also recurse on the output type to determine a suitable base conversion and then must configure the container appropriately for the contents. +It may also perform additional metadata lookups to determine whether either type conforms to `Hashable`, `Error`, or `ObjectiveCBridgeable` protocols. +For collections, this process may end up recursively attempting to convert each element. + +## Compared to Swift 5.3 + +These are some of the ways in which Swift 5.3 differs from the behavior described above: + +* Casts for which the target type is "more Optional" than the static source type previously produced errors. This disallowed all of the following: injecting an `Int` into an `Int?`, extracting an `Int?` from an opaque `Any` container, and casting an `Array` to an `Array`. This document allows all of these. + +``` +let a = 7 +// Swift 5.3: error: cannot downcast to a more optional type +// Specification: returns true +a is Int? +// Swift 5.3: error: cannot downcast to a more optional type +// Specification: returns false +a is Optional + +let b: Int? = 7 +let c: Any = b +// Swift 5.3: error: cannot downcast to a more optional type +// Specification: returns true +c is Int? +``` + +* An instance of a CoreFoundation type could sometimes be cast to a protocol defined on the companion Obj-C type and sometimes not. To make the behavior consistent, we had to choose one; having such casts always succeed seems more consistent with the general dual nature of Obj-C/CF types. + +``` +import Foundation +protocol P {} +extension NSString: P {} +let a = CFStringCreateWithCString(nil, "hello, world", + CFStringBuiltInEncodings.UTF8.rawValue) +// Swift 5.3: prints "true" +print(a is P) +let b: Any = a +// Swift 5.3: prints "false" +// Specification: prints "true" +print(b is P) +``` + +* The Swift 5.3 compiler asserts attempting to cast a struct to AnyObject + +``` +struct S {} +let s = S() +// Swift 5.3: Compiler crash (in asserts build) +// Specification: Succeeds via _SwiftValue boxing +s as? AnyObject +``` + +* `NSNumber()` does not cast to itself via `as?` in unoptimized builds + +``` +import Foundation +let a = NSNumber() +// true in 5.3 for optimized builds; false for unoptimized builds +print((a as? NSNumber) != nil) +``` + +* `Optional` does not project + +``` +import Foundation +let a: Optional = NSNumber() +// Swift 5.3: false +// Specification: true +print(a is NSNumber) +// Swift 5.3: nil +// Specification: .some(NSNumber()) +print(a as? NSNumber) +``` + +* Casting `NSNumber()` to `Any` crashes at runtime + +``` +import Foundation +let a = NSNumber() +// Swift 5.3: Runtime crash (both optimized and unoptimized builds) +// Specification: Succeeds +print(a is Any) +``` + +* SR-2289: CF types cannot be cast to protocol existentials + +``` +import Foundation +protocol P {} +extension CFBitVector : P { + static func makeImmutable(from values: Array) -> CFBitVector { + return CFBitVectorCreate(nil, values, values.count * 8) + } +} +// Swift 5.3: Crashes in unoptimized build, prints true in optimized build +// Specification: prints true +print(CFBitVector.makeImmutable(from: [10,20]) is P) +``` + +* SR-4552: Cannot cast `Optional as Any` to protocol type. Note that this is a particular problem for reflection with weak fields, since `Mirror` reflects those as `Any` containing an `Optional` value. + +``` +protocol P {} +class C: P {} +let c: C? = C() +let a = c as? Any +// Swift 5.3: prints "false" +// Specification: prints "true" +print(a is P) +``` + +* SR-8964: `Any` containing `Optional` cannot cast to `Error` + +``` +struct MyError: Error { } +let a: Any? = MyError() +let b: Any = a +// Swift 5.3: Prints false +// Specification: prints true +print(b is Error) +``` + +* SR-6126: Inconsistent results for nested optionals + +``` +// Note: SR-6126 includes many cases similar to the following +let x: Int? = nil +print(x as Int??) // ==> "Optional(nil)" +// Swift 5.3: prints "nil" +// Specification: should print "Optional(nil)" (same as above) +print((x as? Int??)!) +``` + +* `Error.self` does not fully self-conform + +``` +// Swift 5.3: Prints "false" +// Specification: prints "true" +print(Error.self is Error.Type) +``` + +* Objective-C protocol metatypes do not fully self-conform + +``` +import Foundation +let a = NSObjectProtocol.self +print(a is NSObjectProtocol.Type) +``` + +* SR-1999: Cannot cast `Any` contents to a protocol type + +``` +protocol P {} +class Foo: P {} +let optionalFoo: Foo? = Foo() +let any: Any = optionalFoo +// Swift 5.3: Prints "false" +// Specification: prints "true" +print(any as? P) +``` + +* XXX TODO List others diff --git a/docs/README.md b/docs/README.md index b3e2c3f976d4d..d5b028f34b736 100644 --- a/docs/README.md +++ b/docs/README.md @@ -159,6 +159,8 @@ documentation, please create a thread on the Swift forums under the Documents the Swift Intermediate Language (SIL). - [TransparentAttr.md](/docs/TransparentAttr.md): Documents the semantics of the `@_transparent` attribute. +- [DynamicCasting.md](/docs/DynamicCasting.md): + Behavior of the dynamic casting operators `is`, `as?`, and `as!`. - [Runtime.md](/docs/Runtime.md): Describes the ABI interface to the Swift runtime. From 4d2753b2274ce016ca710c133e95e703f7d9c5d0 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Sun, 16 Aug 2020 20:34:27 -0700 Subject: [PATCH 194/663] Remove updateForPredTerminators in ARCSequenceOpts Historically TermInsts were handled specially while visiting blocks in bottom up order. TermInsts were not visited while traversing a block. They were visited while traversing successors, and the most conservative terminator of all predecessors would affect the refcount state in the dataflow. This was needed because ARCSequenceOpts also computed 'insertion points' for the purposes of ARC code motion. ARC code motion was then removed from ARCSequenceOpts and this code remained unchanged. With this change, arc significant terminators are handled like all other instructions while processing basic blocks bottom up. Also updateForSameLoopInst, updateForDifferentLoopInst, updateForPredTerminators all serve similar purpose with subtle differences. This change removes some code duplication due to this. Remove code duplication of isARCSignificantTerminator. Create ARCSequenceOptUtils for common utils used in ARCSequenceOpts --- lib/SILOptimizer/ARC/ARCRegionState.cpp | 87 ++----------------- lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp | 48 ++++++++++ lib/SILOptimizer/ARC/ARCSequenceOptUtils.h | 27 ++++++ lib/SILOptimizer/ARC/CMakeLists.txt | 1 + .../ARC/GlobalARCSequenceDataflow.cpp | 70 +++------------ lib/SILOptimizer/ARC/RefCountState.cpp | 34 -------- lib/SILOptimizer/ARC/RefCountState.h | 7 -- 7 files changed, 91 insertions(+), 183 deletions(-) create mode 100644 lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp create mode 100644 lib/SILOptimizer/ARC/ARCSequenceOptUtils.h diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index 783ddf60b7cab..f636bbc6f64d4 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -12,6 +12,7 @@ #define DEBUG_TYPE "arc-sequence-opts" #include "ARCRegionState.h" +#include "ARCSequenceOptUtils.h" #include "RCStateTransitionVisitors.h" #include "swift/Basic/Range.h" #include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" @@ -155,77 +156,6 @@ void ARCRegionState::mergePredTopDown(ARCRegionState &PredRegionState) { // Bottom Up Dataflow // -static bool isARCSignificantTerminator(TermInst *TI) { - switch (TI->getTermKind()) { - case TermKind::UnreachableInst: - // br is a forwarding use for its arguments. It cannot in of itself extend - // the lifetime of an object (just like a phi-node) cannot. - case TermKind::BranchInst: - // A cond_br is a forwarding use for its non-operand arguments in a similar - // way to br. Its operand must be an i1 that has a different lifetime from any - // ref counted object. - case TermKind::CondBranchInst: - return false; - // Be conservative for now. These actually perform some sort of operation - // against the operand or can use the value in some way. - case TermKind::ThrowInst: - case TermKind::ReturnInst: - case TermKind::UnwindInst: - case TermKind::YieldInst: - case TermKind::TryApplyInst: - case TermKind::SwitchValueInst: - case TermKind::SwitchEnumInst: - case TermKind::SwitchEnumAddrInst: - case TermKind::DynamicMethodBranchInst: - case TermKind::CheckedCastBranchInst: - case TermKind::CheckedCastValueBranchInst: - case TermKind::CheckedCastAddrBranchInst: - return true; - } - - llvm_unreachable("Unhandled TermKind in switch."); -} - -// Visit each one of our predecessor regions and see if any are blocks that can -// use reference counted values. If any of them do, we advance the sequence for -// the pointer. This state will be propagated -// into all of our predecessors, allowing us to be conservatively correct in all -// cases. -// -// The key thing to notice is that in general this cannot happen due to -// critical edge splitting. To trigger this, one would need a terminator that -// uses a reference counted value and only has one successor due to critical -// edge splitting. This is just to be conservative when faced with the unknown -// of future changes. -// -// We do not need to worry about loops here, since a loop exit block can only -// have predecessors in the loop itself implying that loop exit blocks at the -// loop region level always have only one predecessor, the loop itself. -void ARCRegionState::processBlockBottomUpPredTerminators( - const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, - ImmutablePointerSetFactory &SetFactory) { - llvm::TinyPtrVector PredTerminators; - for (unsigned PredID : R->getPreds()) { - auto *PredRegion = LRFI->getRegion(PredID); - if (!PredRegion->isBlock()) - continue; - - auto *TermInst = PredRegion->getBlock()->getTerminator(); - if (!isARCSignificantTerminator(TermInst)) - continue; - PredTerminators.push_back(TermInst); - } - - for (auto &OtherState : getBottomupStates()) { - // If the other state's value is blotted, skip it. - if (!OtherState.hasValue()) - continue; - - OtherState->second.updateForPredTerminators(PredTerminators, - SetFactory, AA); - } -} - static bool processBlockBottomUpInsts( ARCRegionState &State, SILBasicBlock &BB, BottomUpDataflowRCStateVisitor &DataflowVisitor, @@ -239,9 +169,9 @@ static bool processBlockBottomUpInsts( if (II == IE) return false; - // If II is the terminator, skip it since our terminator was already processed - // in our successors. - if (*II == BB.getTerminator()) + // If II is not an arc significant terminator, skip it. + if (*II == BB.getTerminator() && + !isARCSignificantTerminator(cast(*II))) ++II; bool NestingDetected = false; @@ -298,17 +228,10 @@ bool ARCRegionState::processBlockBottomUp( RCIA, EAFI, *this, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, SetFactory); - // Visit each non-terminator arc relevant instruction I in BB visited in - // reverse... + // Visit each arc relevant instruction I in BB visited in reverse... bool NestingDetected = processBlockBottomUpInsts(*this, BB, DataflowVisitor, AA, SetFactory); - // Now visit each one of our predecessor regions and see if any are blocks - // that can use reference counted values. If any of them do, we advance the - // sequence for the pointer. This state will be propagated into all of our - // predecessors, allowing us to be conservatively correct in all cases. - processBlockBottomUpPredTerminators(R, AA, LRFI, SetFactory); - return NestingDetected; } diff --git a/lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp new file mode 100644 index 0000000000000..ff04e27b99264 --- /dev/null +++ b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.cpp @@ -0,0 +1,48 @@ +//===--- ARCSequenceOptUtils.cpp - ARCSequenceOpt utilities ------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "ARCSequenceOptUtils.h" + +using namespace swift; +namespace swift { +bool isARCSignificantTerminator(TermInst *TI) { + switch (TI->getTermKind()) { + case TermKind::UnreachableInst: + // br is a forwarding use for its arguments. It cannot in of itself extend + // the lifetime of an object (just like a phi-node) cannot. + case TermKind::BranchInst: + // A cond_br is a forwarding use for its non-operand arguments in a similar + // way to br. Its operand must be an i1 that has a different lifetime from any + // ref counted object. + case TermKind::CondBranchInst: + return false; + // Be conservative for now. These actually perform some sort of operation + // against the operand or can use the value in some way. + case TermKind::ThrowInst: + case TermKind::ReturnInst: + case TermKind::UnwindInst: + case TermKind::YieldInst: + case TermKind::TryApplyInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastValueBranchInst: + case TermKind::CheckedCastAddrBranchInst: + return true; + } + + llvm_unreachable("Unhandled TermKind in switch."); +} + +} // end namespace 'swift' diff --git a/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h new file mode 100644 index 0000000000000..9c949da165c5d --- /dev/null +++ b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h @@ -0,0 +1,27 @@ +//===--- ARCSequenceOptUtils.h - ARCSequenceOpts utilities ----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the ARCSequenceOpts for analyzing and transforming +/// SILInstructions. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_ARC_ARCSEQUENCEOPTUTILS_H +#define SWIFT_SILOPTIMIZER_ARC_ARCSEQUENCEOPTUTILS_H + +#include "swift/SIL/SILInstruction.h" + +namespace swift { + bool isARCSignificantTerminator(TermInst *TI); +} // end namespace swift + +#endif diff --git a/lib/SILOptimizer/ARC/CMakeLists.txt b/lib/SILOptimizer/ARC/CMakeLists.txt index 2d3c592834b1b..bc14ca17698ac 100644 --- a/lib/SILOptimizer/ARC/CMakeLists.txt +++ b/lib/SILOptimizer/ARC/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(swiftSILOptimizer PRIVATE ARCMatchingSet.cpp ARCRegionState.cpp ARCSequenceOpts.cpp + ARCSequenceOptUtils.cpp GlobalARCSequenceDataflow.cpp GlobalLoopARCSequenceDataflow.cpp RCStateTransition.cpp diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp index 777548d884bdd..a6e725e44b619 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "arc-sequence-opts" #include "GlobalARCSequenceDataflow.h" #include "ARCBBState.h" +#include "ARCSequenceOptUtils.h" #include "RCStateTransitionVisitors.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" @@ -195,39 +196,6 @@ bool ARCSequenceDataflowEvaluator::processTopDown() { // Bottom Up Dataflow //===----------------------------------------------------------------------===// -// This is temporary code duplication. This will be removed when Loop ARC is -// finished and Block ARC is removed. -static bool isARCSignificantTerminator(TermInst *TI) { - switch (TI->getTermKind()) { - case TermKind::UnreachableInst: - // br is a forwarding use for its arguments. It cannot in of itself extend - // the lifetime of an object (just like a phi-node) cannot. - case TermKind::BranchInst: - // A cond_br is a forwarding use for its non-operand arguments in a similar - // way to br. Its operand must be an i1 that has a different lifetime from any - // ref counted object. - case TermKind::CondBranchInst: - return false; - // Be conservative for now. These actually perform some sort of operation - // against the operand or can use the value in some way. - case TermKind::ThrowInst: - case TermKind::ReturnInst: - case TermKind::UnwindInst: - case TermKind::YieldInst: - case TermKind::TryApplyInst: - case TermKind::SwitchValueInst: - case TermKind::SwitchEnumInst: - case TermKind::SwitchEnumAddrInst: - case TermKind::DynamicMethodBranchInst: - case TermKind::CheckedCastBranchInst: - case TermKind::CheckedCastValueBranchInst: - case TermKind::CheckedCastAddrBranchInst: - return true; - } - - llvm_unreachable("Unhandled TermKind in switch."); -} - /// Analyze a single BB for refcount inc/dec instructions. /// /// If anything was found it will be added to DecToIncStateMap. @@ -254,8 +222,15 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( RCIA, EAFI, BBState, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, SetFactory); - // For each terminator instruction I in BB visited in reverse... - for (auto II = std::next(BB.rbegin()), IE = BB.rend(); II != IE;) { + auto II = BB.rbegin(); + if (isa(*II)) { + if (!isARCSignificantTerminator(&cast(*II))) { + II++; + } + } + + // For each instruction I in BB visited in reverse... + for (auto IE = BB.rend(); II != IE;) { SILInstruction &I = *II; ++II; @@ -292,31 +267,6 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( } } - // This is ignoring the possibility that we may have a loop with an - // interesting terminator but for which, we are going to clear all state - // (since it is a loop boundary). We may in such a case, be too conservative - // with our other predecessors. Luckily this cannot happen since cond_br is - // the only terminator that allows for critical edges and all other - // "interesting terminators" always having multiple successors. This means - // that this block could not have multiple predecessors since otherwise, the - // edge would be broken. - llvm::TinyPtrVector PredTerminators; - for (SILBasicBlock *PredBB : BB.getPredecessorBlocks()) { - auto *TermInst = PredBB->getTerminator(); - if (!isARCSignificantTerminator(TermInst)) - continue; - PredTerminators.push_back(TermInst); - } - - for (auto &OtherState : BBState.getBottomupStates()) { - // If the other state's value is blotted, skip it. - if (!OtherState.hasValue()) - continue; - - OtherState->second.updateForPredTerminators(PredTerminators, - SetFactory, AA); - } - return NestingDetected; } diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index 2406236c6851d..58ef94b453af5 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -500,40 +500,6 @@ void BottomUpRefCountState::updateForDifferentLoopInst( << getRCRoot()); } -void BottomUpRefCountState::updateForPredTerminators( - ArrayRef Terms, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { - // If this state is not tracking anything, there is nothing to update. - if (!isTrackingRefCount()) - return; - - if (valueCanBeGuaranteedUsedGivenLatticeState() && - std::any_of(Terms.begin(), Terms.end(), - [this, &AA](SILInstruction *I) -> bool { - return mayGuaranteedUseValue(I, getRCRoot(), AA); - })) { - handleGuaranteedUser(getRCRoot(), SetFactory, AA); - return; - } - - if (valueCanBeDecrementedGivenLatticeState() && - std::any_of(Terms.begin(), Terms.end(), - [this, &AA](SILInstruction *I) -> bool { - return mayDecrementRefCount(I, getRCRoot(), AA); - })) { - handleDecrement(); - return; - } - - if (!valueCanBeUsedGivenLatticeState() || - std::none_of(Terms.begin(), Terms.end(), - [this, &AA](SILInstruction *I) - -> bool { return mayHaveSymmetricInterference(I, getRCRoot(), AA); })) - return; - - handleUser(getRCRoot(), SetFactory, AA); -} - //===----------------------------------------------------------------------===// // Top Down Ref Count State //===----------------------------------------------------------------------===// diff --git a/lib/SILOptimizer/ARC/RefCountState.h b/lib/SILOptimizer/ARC/RefCountState.h index 1bfb1ab44e133..c987c8f477795 100644 --- a/lib/SILOptimizer/ARC/RefCountState.h +++ b/lib/SILOptimizer/ARC/RefCountState.h @@ -205,13 +205,6 @@ class BottomUpRefCountState : public RefCountState { ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); - // Determine the conservative effect of the given list of predecessor - // terminators upon this reference count. - void updateForPredTerminators( - ArrayRef PredTerms, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); - /// Attempt to merge \p Other into this ref count state. Return true if we /// succeed and false otherwise. bool merge(const BottomUpRefCountState &Other); From 9ef0fce7b0d3a42d1320f21d67062ca98d65f7e8 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 17 Aug 2020 15:41:33 -0700 Subject: [PATCH 195/663] [Function builders] Allow `build` functions to be declared elsewhere. Make the lookup of the various `build` functions for function builders normal, qualified name lookup. This allows (e.g.) the implementation of many of the 'build' functions to come from a protocol extension, making function builders more composable. Thank you to @anreitersimon on the Swift forums for the example! --- lib/Sema/BuilderTransform.cpp | 6 ++- test/Constraints/function_builder.swift | 64 +++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 4c976d26a0f1d..6e8c291c9b36b 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -146,7 +146,11 @@ class BuilderClosureVisitor } bool found = false; - for (auto decl : builder->lookupDirect(fnName)) { + SmallVector foundDecls; + dc->lookupQualified( + builderType, DeclNameRef(fnName), + NL_QualifiedDefault | NL_ProtocolMembers, foundDecls); + for (auto decl : foundDecls) { if (auto func = dyn_cast(decl)) { // Function must be static. if (!func->isStatic()) diff --git a/test/Constraints/function_builder.swift b/test/Constraints/function_builder.swift index eb5e6857c55c1..f59372bd0ff7f 100644 --- a/test/Constraints/function_builder.swift +++ b/test/Constraints/function_builder.swift @@ -703,5 +703,69 @@ tuplify(true) { c in } } +// Test the use of function builders partly implemented through a protocol. +indirect enum FunctionBuilder { + case expression(Expression) + case block([FunctionBuilder]) + case either(Either) + case optional(FunctionBuilder?) +} + +protocol FunctionBuilderProtocol { + associatedtype Expression + typealias Component = FunctionBuilder + associatedtype Return + + static func buildExpression(_ expression: Expression) -> Component + static func buildBlock(_ components: Component...) -> Component + static func buildDo(_ components: Component...) -> Component + static func buildOptional(_ optional: Component?) -> Component + static func buildArray(_ components: [Component]) -> Component + static func buildLimitedAvailability(_ component: Component) -> Component + + static func buildFinalResult(_ components: Component) -> Return +} + +extension FunctionBuilderProtocol { + static func buildExpression(_ expression: Expression) -> Component { .expression(expression) } + static func buildBlock(_ components: Component...) -> Component { .block(components) } + static func buildDo(_ components: Component...) -> Component { .block(components) } + static func buildOptional(_ optional: Component?) -> Component { .optional(optional) } + static func buildArray(_ components: [Component]) -> Component { .block(components) } + static func buildLimitedAvailability(_ component: Component) -> Component { component } +} + +@_functionBuilder +enum ArrayBuilder: FunctionBuilderProtocol { + typealias Expression = E + typealias Component = FunctionBuilder + typealias Return = [E] + + static func buildFinalResult(_ components: Component) -> Return { + switch components { + case .expression(let e): return [e] + case .block(let children): return children.flatMap(buildFinalResult) + case .either(.first(let child)): return buildFinalResult(child) + case .either(.second(let child)): return buildFinalResult(child) + case .optional(let child?): return buildFinalResult(child) + case .optional(nil): return [] + } + } +} + + +func buildArray(@ArrayBuilder build: () -> [String]) -> [String] { + return build() +} +let a = buildArray { + "1" + "2" + if Bool.random() { + "maybe 3" + } +} +// CHECK: ["1", "2" +print(a) + From b1b66202cbeb6f25df0f8a7f7e220a4771f49cde Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 17 Aug 2020 23:52:47 +0000 Subject: [PATCH 196/663] build: allow using the old toolchain on the rebranched LLVM --- utils/build-windows-rebranch.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/build-windows-rebranch.bat b/utils/build-windows-rebranch.bat index 1b2023bf2b1c5..98b08e8334570 100644 --- a/utils/build-windows-rebranch.bat +++ b/utils/build-windows-rebranch.bat @@ -176,6 +176,7 @@ cmake^ -DLLVM_ENABLE_OCAMLDOC:BOOL=NO^ -DLLVM_ENABLE_LIBXML2:BOOL=NO^ -DLLVM_ENABLE_ZLIB:BOOL=NO^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -DENABLE_X86_RELAX_RELOCATIONS:BOOL=YES^ -DLLVM_INSTALL_BINUTILS_SYMLINKS:BOOL=YES^ -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ From 4cfaeee6df2df79d328d6db474e3aae3a437a226 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Mon, 17 Aug 2020 17:34:11 -0700 Subject: [PATCH 197/663] Match the #ifdefs between _swift_isNonPointerIsaObjCClass and objectUsesNativeSwiftReferenceCounting (#33510) --- stdlib/public/runtime/Private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 4be3fb6bdb025..c46e8ff9a9b38 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -211,7 +211,7 @@ class TypeInfo { static inline bool objectUsesNativeSwiftReferenceCounting(const void *object) { assert(!isObjCTaggedPointerOrNull(object)); -#if SWIFT_HAS_OPAQUE_ISAS +#if SWIFT_OBJC_INTEROP && SWIFT_HAS_OPAQUE_ISAS // Fast path for opaque ISAs. We don't want to call // _swift_getClassOfAllocated as that will call object_getClass. // Instead we can look at the bits in the ISA and tell if its a From a434ee8598b246e8c3ee57e59a1caf6b9a3e9ca4 Mon Sep 17 00:00:00 2001 From: Alex Efremov Date: Tue, 18 Aug 2020 03:31:12 +0200 Subject: [PATCH 198/663] [AutoDiff] Fix `PullbackCloner` tangent value category mismatch crash (#33512) Fix semantic member getter pullback generation crash due to tangent value category mismatch. Resolves SR-13411. --- lib/SIL/IR/SILFunctionType.cpp | 1 + lib/SILOptimizer/Differentiation/PullbackCloner.cpp | 4 ++-- .../sr13411-tangent-value-category-mismatch.swift | 12 ++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 test/AutoDiff/compiler_crashers_fixed/sr13411-tangent-value-category-mismatch.swift diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index f14dc7119f89b..2d3e10054313d 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -407,6 +407,7 @@ static CanSILFunctionType getAutoDiffDifferentialType( // result's convention is indirect. if (tl.isAddressOnly() && !isIndirectFormalResult(origResConv)) { switch (origResConv) { + case ResultConvention::Unowned: case ResultConvention::Owned: return ResultConvention::Indirect; default: diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index c753022f042da..9de979b76d0f8 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -2431,7 +2431,7 @@ bool PullbackCloner::Implementation::runForSemanticMemberGetter() { // Switch based on the base tangent struct's value category. // TODO(TF-1255): Simplify using unified adjoint value data structure. - switch (tangentVectorSILTy.getCategory()) { + switch (getTangentValueCategory(origSelf)) { case SILValueCategory::Object: { auto adjResult = getAdjointValue(origEntry, origResult); switch (adjResult.getKind()) { @@ -2472,7 +2472,7 @@ bool PullbackCloner::Implementation::runForSemanticMemberGetter() { if (field == tanField) { // Switch based on the property's value category. // TODO(TF-1255): Simplify using unified adjoint value data structure. - switch (origResult->getType().getCategory()) { + switch (getTangentValueCategory(origResult)) { case SILValueCategory::Object: { auto adjResult = getAdjointValue(origEntry, origResult); auto adjResultValue = materializeAdjointDirect(adjResult, pbLoc); diff --git a/test/AutoDiff/compiler_crashers_fixed/sr13411-tangent-value-category-mismatch.swift b/test/AutoDiff/compiler_crashers_fixed/sr13411-tangent-value-category-mismatch.swift new file mode 100644 index 0000000000000..a7678c55ffd6e --- /dev/null +++ b/test/AutoDiff/compiler_crashers_fixed/sr13411-tangent-value-category-mismatch.swift @@ -0,0 +1,12 @@ +// RUN: %target-build-swift %s +// REQUIRES: asserts + +// SR-13411: Semantic member getter pullback generation crash due to tangent value category mismatch + +import _Differentiation + +struct Dense: Differentiable { + @differentiable + var bias: Float? +} + From 0701eb7d4cc5753d528073afd6f3ff3be338bfc1 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 17 Aug 2020 17:17:38 -0700 Subject: [PATCH 199/663] [utils/api_checker] Adjust the script for inferring imports from an SDK and add a couple of utility scripts --- utils/api_checker/dump-sdk.sh | 65 +++++++++++++++++++ .../sdk-module-lists/create-module-lists.sh | 13 ++++ .../fixed-clang-modules-appletvos.txt | 4 +- .../fixed-clang-modules-iosmac.txt | 2 + .../fixed-clang-modules-iphoneos.txt | 4 +- .../fixed-clang-modules-macosx.txt | 2 + .../sdk-module-lists/infer-imports.py | 7 +- 7 files changed, 92 insertions(+), 5 deletions(-) create mode 100755 utils/api_checker/dump-sdk.sh create mode 100755 utils/api_checker/sdk-module-lists/create-module-lists.sh diff --git a/utils/api_checker/dump-sdk.sh b/utils/api_checker/dump-sdk.sh new file mode 100755 index 0000000000000..5757eb23bdad4 --- /dev/null +++ b/utils/api_checker/dump-sdk.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +DIR="$( cd "$( dirname "$0" )" && pwd )" +sh "$DIR/sdk-module-lists/create-module-lists.sh" + +MacSDKPath=$(xcrun -sdk macosx -show-sdk-path) +IphoneOSSDKPath=$(xcrun -sdk iphoneos -show-sdk-path) +AppleTVOSSDKPath=$(xcrun -sdk appletvos -show-sdk-path) +WathOSSDKPath=$(xcrun -sdk watchos -show-sdk-path) + +XCTestMac="$MacSDKPath/../../Library/Frameworks/" +XCTestIphone="$IphoneOSSDKPath/../../Library/Frameworks/" +XCTestTV="$AppleTVOSSDKPath/../../Library/Frameworks/" + +BASEDIR="$DIR/../../swift-sdk-digests/" + +mkdir -p "${BASEDIR}" + +DumpDir="/tmp/SDKDump" +rm -rf "/tmp/SDKDump" +mkdir "/tmp/SDKDump" + +XCODE_VER=$(xcodebuild -version | sed '1d' | sed 's/Build version //g') + +SWIFT_VER=${SWIFT_VER-3} +echo "SWIFT VERSION: ${SWIFT_VER}" + +function sdk_info() { + echo "Xcode Build: $XCODE_VER" + echo "macOS SDK Build: $(xcodebuild -version -sdk macosx ProductBuildVersion)" + echo "iOS SDK Build: $(xcodebuild -version -sdk iphoneos ProductBuildVersion)" + echo "watchOS SDK Build: $(xcodebuild -version -sdk watchos ProductBuildVersion)" + echo "tvOS SDK Build: $(xcodebuild -version -sdk appletvos ProductBuildVersion)" +} + +sdk_info + +XCODE_VER=-base-$SWIFT_VER + +if [[ -z "$MODULE" ]]; then + $SWIFT_API_DIGESTER -target x86_64-apple-macosx10.15 -o "$BASEDIR/macos$XCODE_VER.json" -dump-sdk -sdk "$MacSDKPath" -module-list-file "/tmp/modules-osx.txt" -F "$XCTestMac" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-ios13.5 -o "$BASEDIR/ios$XCODE_VER.json" -dump-sdk -sdk "$IphoneOSSDKPath" -module-list-file "/tmp/modules-iphoneos.txt" -F "$XCTestIphone" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-tvos13.4 -o "$BASEDIR/tvos$XCODE_VER.json" -dump-sdk -sdk "$AppleTVOSSDKPath" -module-list-file "/tmp/modules-tvos.txt" -F "$XCTestTV" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target armv7k-apple-watchos6.2 -o "$BASEDIR/watchos$XCODE_VER.json" -dump-sdk -sdk "$WathOSSDKPath" -module-list-file "/tmp/modules-watchos.txt" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target x86_64-apple-macosx10.15 -o "$BASEDIR/macos-stdlib$XCODE_VER.json" -dump-sdk -sdk "$MacSDKPath" -module Swift -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER +else + ALL_MODULE_DIR="$BASEDIR/Xcode$XCODE_VER" + rm -rf "$ALL_MODULE_DIR" + mkdir "$ALL_MODULE_DIR" + declare -a MODULE_NAMES=("Accelerate" "Foundation" "AppKit" "UIKit" "AudioToolbox" "Automator" "AVFoundation" + "AVKit" "CloudKit" "CoreBluetooth" "GameKit" "iAd" "Metal" "MetalKit" + "MetalPerformanceShaders" "OpenGLES" "Quartz" "XCTest" "UserNotifications" "CoreMedia" "VideoToolbox" "MediaToolbox" "MapKit") + for MODULE in "${MODULE_NAMES[@]}" + do + echo "Generating baseline for framework ${MODULE}" + MODULE_DIR="$ALL_MODULE_DIR/$MODULE" + rm -rf "$MODULE_DIR" + mkdir "$MODULE_DIR" + $SWIFT_API_DIGESTER -target x86_64-apple-macosx10.15 -o "$MODULE_DIR/macos.json" -dump-sdk -sdk "$MacSDKPath" -module "$MODULE" -F "$XCTestMac" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-ios13.5 -o "$MODULE_DIR/ios.json" -dump-sdk -sdk "$IphoneOSSDKPath" -module "$MODULE" -F "$XCTestIphone" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target arm64-apple-tvos13.4 -o "$MODULE_DIR/tvos.json" -dump-sdk -sdk "$AppleTVOSSDKPath" -module "$MODULE" -F "$XCTestTV" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + $SWIFT_API_DIGESTER -target armv7k-apple-watchos6.2 -o "$MODULE_DIR/watchos.json" -dump-sdk -sdk "$WathOSSDKPath" -module "$MODULE" -module-cache-path "$DumpDir/ModuleCache" -swift-version $SWIFT_VER + done +fi diff --git a/utils/api_checker/sdk-module-lists/create-module-lists.sh b/utils/api_checker/sdk-module-lists/create-module-lists.sh new file mode 100755 index 0000000000000..c794567fcb043 --- /dev/null +++ b/utils/api_checker/sdk-module-lists/create-module-lists.sh @@ -0,0 +1,13 @@ +DIR="$( cd "$( dirname "$0" )" && pwd )" +$DIR/infer-imports.py -s $(xcrun --sdk macosx --show-sdk-path) > /tmp/modules-osx.txt && \ +$DIR/infer-imports.py -s $(xcrun --sdk iphoneos --show-sdk-path) > /tmp/modules-iphoneos.txt && \ +$DIR/infer-imports.py -s $(xcrun --sdk appletvos --show-sdk-path) > /tmp/modules-tvos.txt && \ +$DIR/infer-imports.py -s $(xcrun --sdk watchos --show-sdk-path) > /tmp/modules-watchos.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-osx.txt && \ +cat $DIR/fixed-clang-modules-macosx.txt >> /tmp/modules-osx.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-iphoneos.txt && \ +cat $DIR/fixed-clang-modules-iphoneos.txt >> /tmp/modules-iphoneos.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-tvos.txt && \ +cat $DIR/fixed-clang-modules-appletvos.txt >> /tmp/modules-tvos.txt && \ +cat $DIR/fixed-clang-modules-common.txt >> /tmp/modules-watchos.txt && \ +cat $DIR/fixed-clang-modules-watchos.txt >> /tmp/modules-watchos.txt diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt index 5154bd4dff5d3..7c352a57bb1d6 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-appletvos.txt @@ -1 +1,3 @@ -XCTest \ No newline at end of file +XCTest +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt index d15abba59766b..bef2b6a46493e 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iosmac.txt @@ -1 +1,3 @@ // Empty +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt index 5154bd4dff5d3..7c352a57bb1d6 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-iphoneos.txt @@ -1 +1,3 @@ -XCTest \ No newline at end of file +XCTest +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt b/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt index 14aaee023d9ca..23fa920569b58 100644 --- a/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt +++ b/utils/api_checker/sdk-module-lists/fixed-clang-modules-macosx.txt @@ -1,2 +1,4 @@ XPC XCTest +SceneKit.ModelIO +CoreImage.CIFilterBuiltins diff --git a/utils/api_checker/sdk-module-lists/infer-imports.py b/utils/api_checker/sdk-module-lists/infer-imports.py index a923c6b2f441c..c85348db9bcce 100755 --- a/utils/api_checker/sdk-module-lists/infer-imports.py +++ b/utils/api_checker/sdk-module-lists/infer-imports.py @@ -8,7 +8,8 @@ denylist = [ "Kernel", "Ruby", "Tk", "DriverKit", "HIDDriverKit", "SkywalkDriverKit", # has C++ code - "NetworkingDriverKit", "USBSerialDriverKit", # has C++ code + "NetworkingDriverKit", "USBSerialDriverKit", "PCIDriverKit", # has C++ code + "USBDriverKit", # has C++ code ] @@ -46,6 +47,8 @@ def get_frameworks(sdk_path, swift_frameworks_only): frameworks_path = sdk_path + "/System/Library/Frameworks" names = [] for frame in os.listdir(frameworks_path): + if frame[0] == '_': + continue if frame.endswith(".framework"): name = frame[:-len(".framework")] header_dir_path = frameworks_path + '/' + frame + '/Headers' @@ -106,8 +109,6 @@ def should_exclude_framework(frame_path): contents = open(module_map_path).read() if "requires !swift" in contents: return True - if "requires unavailable" in contents: - return True return False From 53cdd770446d76970e6e43ab6272fbaa8529a5ee Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Mon, 17 Aug 2020 22:46:13 -0300 Subject: [PATCH 200/663] [CSDiagnostics] Also consider PartialKeyPath a non-writable keypath on AssignmentFailure diagnostics --- lib/Sema/CSDiagnostics.cpp | 4 +++- test/expr/unary/keypath/keypath.swift | 24 ++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 80bcf26c217d0..0a0b254e5a5ee 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1860,7 +1860,9 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { // In Swift versions lower than 5, this check will fail as read only // key paths can masquerade as writable for compatibilty reasons. // This is fine as in this case we just fall back on old diagnostics. - if (bgt->getDecl() == getASTContext().getKeyPathDecl()) { + auto &ctx = getASTContext(); + if (bgt->getDecl() == ctx.getKeyPathDecl() || + bgt->getDecl() == ctx.getPartialKeyPathDecl()) { return {expr, member}; } } diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index 94b1824038e4f..9b0333b0c0de4 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -324,8 +324,8 @@ func testKeyPathSubscript(readonly: Z, writable: inout Z, var anySink2 = writable[keyPath: pkp] expect(&anySink2, toHaveType: Exactly.self) - readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}} - writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: 'writable' is immutable}} + readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: 'pkp' is a read-only key path}} + writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: 'pkp' is a read-only key path}} let akp: AnyKeyPath = pkp @@ -443,12 +443,12 @@ func testKeyPathSubscriptLValue(base: Z, kp: inout KeyPath) { } func testKeyPathSubscriptExistentialBase(concreteBase: inout B, - existentialBase: inout P, - kp: KeyPath, - wkp: WritableKeyPath, - rkp: ReferenceWritableKeyPath, - pkp: PartialKeyPath

, - s: String) { + existentialBase: inout P, + kp: KeyPath, + wkp: WritableKeyPath, + rkp: ReferenceWritableKeyPath, + pkp: PartialKeyPath

Note: This is in reverse chronological order, so newer entries are added to the top. -| Version | Released | Toolchain | -| :--------------------- | :--------- | :---------- | -| [Swift 5.3](#swift-53) | | | -| [Swift 5.2](#swift-52) | 2020-03-24 | Xcode 11.4 | -| [Swift 5.1](#swift-51) | 2019-09-20 | Xcode 11.0 | -| [Swift 5.0](#swift-50) | 2019-03-25 | Xcode 10.2 | -| [Swift 4.2](#swift-42) | 2018-09-17 | Xcode 10.0 | -| [Swift 4.1](#swift-41) | 2018-03-29 | Xcode 9.3 | -| [Swift 4.0](#swift-40) | 2017-09-19 | Xcode 9.0 | -| [Swift 3.1](#swift-31) | 2017-03-27 | Xcode 8.3 | -| [Swift 3.0](#swift-30) | 2016-09-13 | Xcode 8.0 | -| [Swift 2.2](#swift-22) | 2016-03-21 | Xcode 7.3 | -| [Swift 2.1](#swift-21) | 2015-10-21 | Xcode 7.1 | -| [Swift 2.0](#swift-20) | 2015-09-17 | Xcode 7.0 | -| [Swift 1.2](#swift-12) | 2015-04-08 | Xcode 6.3 | -| [Swift 1.1](#swift-11) | 2014-12-02 | Xcode 6.1.1 | -| [Swift 1.0](#swift-10) | 2014-09-15 | Xcode 6.0 | +| Version | Released | Toolchain | +| :------------------------ | :--------- | :---------- | +| [Swift Next](#swift-next) | +| [Swift 5.3](#swift-53) | | | +| [Swift 5.2](#swift-52) | 2020-03-24 | Xcode 11.4 | +| [Swift 5.1](#swift-51) | 2019-09-20 | Xcode 11.0 | +| [Swift 5.0](#swift-50) | 2019-03-25 | Xcode 10.2 | +| [Swift 4.2](#swift-42) | 2018-09-17 | Xcode 10.0 | +| [Swift 4.1](#swift-41) | 2018-03-29 | Xcode 9.3 | +| [Swift 4.0](#swift-40) | 2017-09-19 | Xcode 9.0 | +| [Swift 3.1](#swift-31) | 2017-03-27 | Xcode 8.3 | +| [Swift 3.0](#swift-30) | 2016-09-13 | Xcode 8.0 | +| [Swift 2.2](#swift-22) | 2016-03-21 | Xcode 7.3 | +| [Swift 2.1](#swift-21) | 2015-10-21 | Xcode 7.1 | +| [Swift 2.0](#swift-20) | 2015-09-17 | Xcode 7.0 | +| [Swift 1.2](#swift-12) | 2015-04-08 | Xcode 6.3 | +| [Swift 1.1](#swift-11) | 2014-12-02 | Xcode 6.1.1 | +| [Swift 1.0](#swift-10) | 2014-09-15 | Xcode 6.0 |
+Swift Next +---------- + +* [SE-0287][]: + + Implicit member expressions now support chains of member accesses, making the following valid: + + ```swift + let milky: UIColor = .white.withAlphaComponent(0.5) + let milky2: UIColor = .init(named: "white")!.withAlphaComponent(0.5) + let milkyChance: UIColor? = .init(named: "white")?.withAlphaComponent(0.5) + ``` + + As is the case with the existing implicit member expression syntax, the resulting type of the chain must be the same as the (implicit) base, so it is not well-formed to write: + + ```swift + let cgMilky: CGColor = .white.withAlphaComponent(0.5).cgColor + ``` + + (Unless, of course, appropriate `white` and `withAlphaComponent` members were defined on `CGColor`.) + + Members of a "chain" can be properties, method calls, subscript accesses, force unwraps, or optional chaining question marks. Furthermore, the type of each member along the chain is permitted to differ (again, as long as the base of the chain matches the resulting type) meaning the following successfully typechecks: + + ```swift + struct Foo { + static var foo = Foo() + static var bar = Bar() + + var anotherFoo: Foo { Foo() } + func getFoo() -> Foo { Foo() } + var optionalFoo: Foo? { Foo() } + subscript() -> Foo { Foo() } + } + + struct Bar { + var anotherFoo = Foo() + } + + let _: Foo? = .bar.anotherFoo.getFoo().optionalFoo?.optionalFoo![] + ``` + Swift 5.3 --------- @@ -8071,6 +8113,7 @@ Swift 1.0 [SE-0269]: [SE-0276]: [SE-0280]: +[SE-0287]: [SR-75]: [SR-106]: From d29bca5a5340489906d2314e9cea566857f1f2af Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sun, 30 Aug 2020 19:06:46 -0700 Subject: [PATCH 471/663] [ownership] Extract out the computation of implicit uses for BorrowingOperands and InteriorPointerOperands into utilities on those classes. I am currently working on updating SimplifyCFG for ownership. One thing that I am finding that I need is the ability to compute the lifetime of a guaranteed argument from a checked_cast_br/switch_enum in order to convert said instructions to a br. The issue comes from br acting as a consuming (lifetime ending) use of a borrowed value, unlike checked_cast_br/switch_enum (which are treated like forwarding instructions). This means that during the conversion we need to insert a begin_borrow on the value before the new br instruction and then create an end_borrow at the end of the successor block's argument's lifetime. By refactoring out this code from the ownership verifier, I can guarantee that said lifetime computation will always match what the ownership verifier does internally preventing them from getting out of sync. --- include/swift/SIL/OwnershipUtils.h | 22 +++ lib/SIL/Utils/OwnershipUtils.cpp | 150 +++++++++++++++++ lib/SIL/Verifier/SILOwnershipVerifier.cpp | 196 ++++------------------ 3 files changed, 201 insertions(+), 167 deletions(-) diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 4f2a36d7282aa..5884a0ad2d700 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -196,6 +196,18 @@ struct BorrowingOperand { void visitConsumingUsesOfBorrowIntroducingUserResults( function_ref visitor) const; + /// Compute the implicit uses that this borrowing operand "injects" into the + /// set of its operands uses. + /// + /// E.x.: end_apply uses. + /// + /// \p errorFunction a callback that if non-null is passed an operand that + /// triggers a mal-formed SIL error. This is just needed for the ownership + /// verifier to emit good output. + bool getImplicitUses( + SmallVectorImpl &foundUses, + std::function *errorFunction = nullptr) const; + void print(llvm::raw_ostream &os) const; SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } @@ -467,6 +479,16 @@ struct InteriorPointerOperand { llvm_unreachable("Covered switch isn't covered?!"); } + /// Compute the list of implicit uses that this interior pointer operand puts + /// on its parent guaranted value. + /// + /// Example: Uses of a ref_element_addr can not occur outside of the lifetime + /// of the instruction's operand. The uses of that address act as liveness + /// requirements to ensure that the underlying class is alive at all use + /// points. + bool getImplicitUses(SmallVectorImpl &foundUses, + std::function *onError = nullptr); + private: /// Internal constructor for failable static constructor. Please do not expand /// its usage since it assumes the code passed in is well formed. diff --git a/lib/SIL/Utils/OwnershipUtils.cpp b/lib/SIL/Utils/OwnershipUtils.cpp index 8ece70a783b50..7cd18ae2376e1 100644 --- a/lib/SIL/Utils/OwnershipUtils.cpp +++ b/lib/SIL/Utils/OwnershipUtils.cpp @@ -12,6 +12,7 @@ #include "swift/SIL/OwnershipUtils.h" #include "swift/Basic/Defer.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/LinearLifetimeChecker.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" @@ -266,6 +267,48 @@ void BorrowingOperand::visitUserResultConsumingUses( } } +bool BorrowingOperand::getImplicitUses( + SmallVectorImpl &foundUses, + std::function *errorFunction) const { + if (!areAnyUserResultsBorrowIntroducers()) { + visitEndScopeInstructions([&](Operand *op) { foundUses.push_back(op); }); + return false; + } + + // Ok, we have an instruction that introduces a new borrow scope and its + // result is that borrow scope. In such a case, we need to not just add the + // end scope instructions of this scoped operand, but also look through any + // guaranteed phis and add their end_borrow to this list as well. + SmallVector worklist; + SmallPtrSet visitedValue; + worklist.push_back(*this); + visitedValue.insert(op); + bool foundError = false; + while (!worklist.empty()) { + auto scopedOperand = worklist.pop_back_val(); + scopedOperand.visitConsumingUsesOfBorrowIntroducingUserResults( + [&](Operand *op) { + if (auto subSub = BorrowingOperand::get(op)) { + if (!visitedValue.insert(op).second) { + if (errorFunction) { + (*errorFunction)(op); + } + foundError = true; + return; + } + + worklist.push_back(*subSub); + visitedValue.insert(subSub->op); + return; + } + + foundUses.push_back(op); + }); + } + + return foundError; +} + //===----------------------------------------------------------------------===// // Borrow Introducers //===----------------------------------------------------------------------===// @@ -459,6 +502,113 @@ bool BorrowedValue::visitInteriorPointerOperands( return true; } +//===----------------------------------------------------------------------===// +// InteriorPointerOperand +//===----------------------------------------------------------------------===// + +bool InteriorPointerOperand::getImplicitUses( + SmallVectorImpl &foundUses, + std::function *onError) { + SILValue projectedAddress = getProjectedAddress(); + SmallVector worklist(projectedAddress->getUses()); + + bool foundError = false; + + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + + // Skip type dependent operands. + if (op->isTypeDependent()) + continue; + + // Before we do anything, add this operand to our implicit regular user + // list. + foundUses.push_back(op); + + // Then update the worklist with new things to find if we recognize this + // inst and then continue. If we fail, we emit an error at the bottom of the + // loop that we didn't recognize the user. + auto *user = op->getUser(); + + // First, eliminate "end point uses" that we just need to check liveness at + // and do not need to check transitive uses of. + if (isa(user) || isa(user) || + isIncidentalUse(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user) || + isa(user)) { + continue; + } + + // Then handle users that we need to look at transitive uses of. + if (Projection::isAddressProjection(user) || + isa(user) || + isa(user) || + isa(user) || isa(user) || + isa(user) || isa(user)) { + for (SILValue r : user->getResults()) { + llvm::copy(r->getUses(), std::back_inserter(worklist)); + } + continue; + } + + if (auto *builtin = dyn_cast(user)) { + if (auto kind = builtin->getBuiltinKind()) { + if (*kind == BuiltinValueKind::TSanInoutAccess) { + continue; + } + } + } + + // If we have a load_borrow, add it's end scope to the liveness requirement. + if (auto *lbi = dyn_cast(user)) { + transform(lbi->getEndBorrows(), std::back_inserter(foundUses), + [](EndBorrowInst *ebi) { return &ebi->getAllOperands()[0]; }); + continue; + } + + // TODO: Merge this into the full apply site code below. + if (auto *beginApply = dyn_cast(user)) { + // TODO: Just add this to implicit regular user list? + llvm::copy(beginApply->getTokenResult()->getUses(), + std::back_inserter(foundUses)); + continue; + } + + if (auto fas = FullApplySite::isa(user)) { + continue; + } + + if (auto *mdi = dyn_cast(user)) { + // If this is the base, just treat it as a liveness use. + if (op->get() == mdi->getBase()) { + continue; + } + + // If we are the value use, look through it. + llvm::copy(mdi->getValue()->getUses(), std::back_inserter(worklist)); + continue; + } + + // We were unable to recognize this user, so return true that we failed. + if (onError) { + (*onError)(op); + } + foundError = true; + } + + // We were able to recognize all of the uses of the address, so return false + // that we did not find any errors. + return foundError; +} + //===----------------------------------------------------------------------===// // Owned Value Introducers //===----------------------------------------------------------------------===// diff --git a/lib/SIL/Verifier/SILOwnershipVerifier.cpp b/lib/SIL/Verifier/SILOwnershipVerifier.cpp index f829349d73051..7e48a583a39db 100644 --- a/lib/SIL/Verifier/SILOwnershipVerifier.cpp +++ b/lib/SIL/Verifier/SILOwnershipVerifier.cpp @@ -152,12 +152,6 @@ class SILValueOwnershipChecker { bool isSubobjectProjectionWithLifetimeEndingUses( SILValue value, const SmallVectorImpl &lifetimeEndingUsers) const; - bool discoverBorrowOperandImplicitRegularUsers( - const BorrowingOperand &initialScopedOperand, - SmallVectorImpl &implicitRegularUsers, bool isGuaranteed); - bool discoverInteriorPointerOperandImplicitRegularUsers( - const InteriorPointerOperand &interiorPointerOperand, - SmallVectorImpl &implicitRegularUsers); }; } // namespace swift @@ -227,161 +221,6 @@ bool SILValueOwnershipChecker::isCompatibleDefUse( return false; } -/// Returns true if an error was found. -bool SILValueOwnershipChecker::discoverBorrowOperandImplicitRegularUsers( - const BorrowingOperand &initialScopedOperand, - SmallVectorImpl &implicitRegularUsers, bool isGuaranteed) { - if (!initialScopedOperand.areAnyUserResultsBorrowIntroducers()) { - initialScopedOperand.visitEndScopeInstructions( - [&](Operand *op) { implicitRegularUsers.push_back(op); }); - return false; - } - - // Ok, we have an instruction that introduces a new borrow scope and its - // result is that borrow scope. In such a case, we need to not just add the - // end scope instructions of this scoped operand, but also look through any - // guaranteed phis and add their end_borrow to this list as well. - SmallVector worklist; - SmallPtrSet visitedValue; - worklist.push_back(initialScopedOperand); - visitedValue.insert(initialScopedOperand.op); - bool foundError = false; - while (!worklist.empty()) { - auto scopedOperand = worklist.pop_back_val(); - scopedOperand.visitConsumingUsesOfBorrowIntroducingUserResults( - [&](Operand *op) { - if (auto subSub = BorrowingOperand::get(op)) { - if (!visitedValue.insert(op).second) { - errorBuilder.handleMalformedSIL([&] { - llvm::errs() - << "Implicit Regular User Guaranteed Phi Cycle!\n" - << "User: " << *op->getUser() - << "Initial: " << initialScopedOperand << "\n"; - }); - foundError = true; - return; - } - - worklist.push_back(*subSub); - visitedValue.insert(subSub->op); - return; - } - - implicitRegularUsers.push_back(op); - }); - } - - return foundError; -} - -bool SILValueOwnershipChecker:: - discoverInteriorPointerOperandImplicitRegularUsers( - const InteriorPointerOperand &interiorPointerOperand, - SmallVectorImpl &implicitRegularUsers) { - SILValue projectedAddress = interiorPointerOperand.getProjectedAddress(); - SmallVector worklist(projectedAddress->getUses()); - - bool foundError = false; - - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - - // Skip type dependent operands. - if (op->isTypeDependent()) - continue; - - // Before we do anything, add this operand to our implicit regular user - // list. - implicitRegularUsers.push_back(op); - - // Then update the worklist with new things to find if we recognize this - // inst and then continue. If we fail, we emit an error at the bottom of the - // loop that we didn't recognize the user. - auto *user = op->getUser(); - - // First, eliminate "end point uses" that we just need to check liveness at - // and do not need to check transitive uses of. - if (isa(user) || isa(user) || - isIncidentalUse(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user) || - isa(user)) { - continue; - } - - // Then handle users that we need to look at transitive uses of. - if (Projection::isAddressProjection(user) || - isa(user) || - isa(user) || - isa(user) || isa(user) || - isa(user) || isa(user)) { - for (SILValue r : user->getResults()) { - llvm::copy(r->getUses(), std::back_inserter(worklist)); - } - continue; - } - - if (auto *builtin = dyn_cast(user)) { - if (auto kind = builtin->getBuiltinKind()) { - if (*kind == BuiltinValueKind::TSanInoutAccess) { - continue; - } - } - } - - // If we have a load_borrow, add it's end scope to the liveness requirement. - if (auto *lbi = dyn_cast(user)) { - transform(lbi->getEndBorrows(), std::back_inserter(implicitRegularUsers), - [](EndBorrowInst *ebi) { return &ebi->getAllOperands()[0]; }); - continue; - } - - // TODO: Merge this into the full apply site code below. - if (auto *beginApply = dyn_cast(user)) { - // TODO: Just add this to implicit regular user list? - llvm::copy(beginApply->getTokenResult()->getUses(), - std::back_inserter(implicitRegularUsers)); - continue; - } - - if (auto fas = FullApplySite::isa(user)) { - continue; - } - - if (auto *mdi = dyn_cast(user)) { - // If this is the base, just treat it as a liveness use. - if (op->get() == mdi->getBase()) { - continue; - } - - // If we are the value use, look through it. - llvm::copy(mdi->getValue()->getUses(), std::back_inserter(worklist)); - continue; - } - - // We were unable to recognize this user, so return true that we failed. - errorBuilder.handleMalformedSIL([&] { - llvm::errs() - << "Could not recognize address user of interior pointer operand!\n" - << "Interior Pointer Operand: " - << *interiorPointerOperand.operand->getUser() - << "Address User: " << *op->getUser(); - }); - foundError = true; - } - - // We were able to recognize all of the uses of the address, so return false - // that we did not find any errors. - return foundError; -} - bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( SmallVectorImpl &lifetimeEndingUsers, SmallVectorImpl &nonLifetimeEndingUsers, @@ -442,8 +281,15 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( // initial end scope instructions without any further work. // // Maybe: Is borrow scope non-local? - foundError |= discoverBorrowOperandImplicitRegularUsers( - *initialScopedOperand, implicitRegularUsers, false); + std::function error = [&](Operand *op) { + errorBuilder.handleMalformedSIL([&] { + llvm::errs() << "Implicit Regular User Guaranteed Phi Cycle!\n" + << "User: " << *op->getUser() + << "Initial: " << *initialScopedOperand << "\n"; + }); + }; + foundError |= + initialScopedOperand->getImplicitUses(implicitRegularUsers, &error); } return foundError; @@ -533,16 +379,32 @@ bool SILValueOwnershipChecker::gatherUsers( if (auto scopedOperand = BorrowingOperand::get(op)) { assert(!scopedOperand->consumesGuaranteedValues()); - foundError |= discoverBorrowOperandImplicitRegularUsers( - *scopedOperand, implicitRegularUsers, true); + std::function onError = [&](Operand *op) { + errorBuilder.handleMalformedSIL([&] { + llvm::errs() << "Implicit Regular User Guaranteed Phi Cycle!\n" + << "User: " << *op->getUser() + << "Initial: " << *scopedOperand << "\n"; + }); + }; + foundError |= + scopedOperand->getImplicitUses(implicitRegularUsers, &onError); } // Next see if our use is an interior pointer operand. If we have an // interior pointer, we need to add all of its address uses as "implicit // regular users" of our consumed value. if (auto interiorPointerOperand = InteriorPointerOperand::get(op)) { - foundError |= discoverInteriorPointerOperandImplicitRegularUsers( - *interiorPointerOperand, implicitRegularUsers); + std::function onError = [&](Operand *op) { + errorBuilder.handleMalformedSIL([&] { + llvm::errs() << "Could not recognize address user of interior " + "pointer operand!\n" + << "Interior Pointer Operand: " + << interiorPointerOperand->operand->getUser() + << "Address User: " << *op->getUser(); + }); + }; + foundError |= interiorPointerOperand->getImplicitUses( + implicitRegularUsers, &onError); } // Finally add the op to the non lifetime ending user list. From cabcbc92707e2e85a203dc99573c57537e1fbf24 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 31 Aug 2020 13:53:37 -0700 Subject: [PATCH 472/663] [Constraint application] Find trailing closure direction more carefully. Rather than trying to include each expression kind, which leaves us open to errors of omission, exclude only the case where we don't record locators for trailing closure directions. --- lib/Sema/CSApply.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 640d7be2bcb82..501ad1a4f5d69 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5592,9 +5592,7 @@ Expr *ExprRewriter::coerceCallArguments( SmallVector path; auto anchor = locator.getLocatorParts(path); if (!path.empty() && path.back().is() && - (anchor.isExpr(ExprKind::Call) || - anchor.isExpr(ExprKind::Subscript) || - anchor.isExpr(ExprKind::UnresolvedMember))) { + !anchor.isExpr(ExprKind::UnresolvedDot)) { auto locatorPtr = cs.getConstraintLocator(locator); assert(solution.trailingClosureMatchingChoices.count(locatorPtr) == 1); trailingClosureMatching = solution.trailingClosureMatchingChoices.find( From 7c12c7f4667a9afaddc658b48bda1ab89f9d0522 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sat, 29 Aug 2020 21:25:40 -0700 Subject: [PATCH 473/663] [semantic-arc] Extract out borrow scope optimizations into its own file. --- .../SemanticARC/BorrowScopeOpts.cpp | 58 +++++++++++++++++++ lib/SILOptimizer/SemanticARC/CMakeLists.txt | 3 +- .../SemanticARC/SemanticARCOpts.cpp | 38 ------------ 3 files changed, 60 insertions(+), 39 deletions(-) create mode 100644 lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp diff --git a/lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp b/lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp new file mode 100644 index 0000000000000..600c6f41d5072 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/BorrowScopeOpts.cpp @@ -0,0 +1,58 @@ +//===--- BorrowScopeOpts.cpp ----------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Optimizations that attempt to simplify and or eliminate borrow scopes. Today +/// we only eliminate scopes, but we could also eliminate redundant scopes by +/// converting struct_extract operations to use destructure operations. +/// +//===----------------------------------------------------------------------===// + +#include "SemanticARCOptVisitor.h" + +using namespace swift; +using namespace swift::semanticarc; + +bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { + auto kind = bbi->getOperand().getOwnershipKind(); + SmallVector endBorrows; + for (auto *op : bbi->getUses()) { + if (!op->isConsumingUse()) { + // Make sure that this operand can accept our arguments kind. + auto map = op->getOwnershipKindMap(); + if (map.canAcceptKind(kind)) + continue; + return false; + } + + // Otherwise, this borrow is being consumed. See if our consuming inst is an + // end_borrow. If it isn't, then return false, this scope is + // needed. Otherwise, add the end_borrow to our list of end borrows. + auto *ebi = dyn_cast(op->getUser()); + if (!ebi) { + return false; + } + endBorrows.push_back(ebi); + } + + // At this point, we know that the begin_borrow's operand can be + // used as an argument to all non-end borrow uses. Eliminate the + // begin borrow and end borrows. + while (!endBorrows.empty()) { + auto *ebi = endBorrows.pop_back_val(); + eraseInstruction(ebi); + } + + eraseAndRAUWSingleValueInstruction(bbi, bbi->getOperand()); + return true; +} diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt index 1291d0660ad69..2244810281658 100644 --- a/lib/SILOptimizer/SemanticARC/CMakeLists.txt +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(swiftSILOptimizer PRIVATE SemanticARCOpts.cpp OwnershipLiveRange.cpp - LoadCopyToLoadBorrowOpt.cpp) + LoadCopyToLoadBorrowOpt.cpp + BorrowScopeOpts.cpp) diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index 431716a388ad6..444cdc6d90b40 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -376,44 +376,6 @@ bool SemanticARCOptVisitor::processWorklist() { return madeChange; } -//===----------------------------------------------------------------------===// -// Redundant Borrow Scope Elimination -//===----------------------------------------------------------------------===// - -bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { - auto kind = bbi->getOperand().getOwnershipKind(); - SmallVector endBorrows; - for (auto *op : bbi->getUses()) { - if (!op->isConsumingUse()) { - // Make sure that this operand can accept our arguments kind. - auto map = op->getOwnershipKindMap(); - if (map.canAcceptKind(kind)) - continue; - return false; - } - - // Otherwise, this borrow is being consumed. See if our consuming inst is an - // end_borrow. If it isn't, then return false, this scope is - // needed. Otherwise, add the end_borrow to our list of end borrows. - auto *ebi = dyn_cast(op->getUser()); - if (!ebi) { - return false; - } - endBorrows.push_back(ebi); - } - - // At this point, we know that the begin_borrow's operand can be - // used as an argument to all non-end borrow uses. Eliminate the - // begin borrow and end borrows. - while (!endBorrows.empty()) { - auto *ebi = endBorrows.pop_back_val(); - eraseInstruction(ebi); - } - - eraseAndRAUWSingleValueInstruction(bbi, bbi->getOperand()); - return true; -} - //===----------------------------------------------------------------------===// // CopyValue Optimizations Elimination //===----------------------------------------------------------------------===// From fb256520e62daf2b10a2e5cab92235d1eb87e68a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 31 Aug 2020 22:20:04 +0100 Subject: [PATCH 474/663] Fix atomicity in IRGen --- lib/IRGen/IRGenModule.h | 6 ++++-- lib/IRGen/IRGenSIL.cpp | 11 +++++------ lib/IRGen/Outlining.cpp | 10 ++++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 82590df971d01..79d6a1cce609c 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1020,10 +1020,12 @@ class IRGenModule { bool setIsNoInline = false); llvm::Constant *getOrCreateRetainFunction(const TypeInfo &objectTI, SILType t, - llvm::Type *llvmType); + llvm::Type *llvmType, + irgen::Atomicity atomicity); llvm::Constant *getOrCreateReleaseFunction(const TypeInfo &objectTI, SILType t, - llvm::Type *llvmType); + llvm::Type *llvmType, + irgen::Atomicity atomicity); llvm::Constant *getOrCreateOutlinedInitializeWithTakeFunction( SILType objectType, const TypeInfo &objectTI, diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 48154c9678dcd..a08c2f95ffe11 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -3629,15 +3629,15 @@ void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) { } void IRGenSILFunction::visitRetainValueAddrInst(swift::RetainValueAddrInst *i) { - assert(i->getAtomicity() == RefCountingInst::Atomicity::Atomic && - "Non atomic retains are not supported"); SILValue operandValue = i->getOperand(); Address addr = getLoweredAddress(operandValue); SILType addrTy = operandValue->getType(); SILType objectT = addrTy.getObjectType(); llvm::Type *llvmType = addr.getAddress()->getType(); const TypeInfo &addrTI = getTypeInfo(addrTy); - auto *outlinedF = IGM.getOrCreateRetainFunction(addrTI, objectT, llvmType); + auto *outlinedF = IGM.getOrCreateRetainFunction( + addrTI, objectT, llvmType, i->isAtomic() ? irgen::Atomicity::Atomic + : irgen::Atomicity::NonAtomic); llvm::Value *args[] = {addr.getAddress()}; llvm::CallInst *call = Builder.CreateCall(outlinedF, args); call->setCallingConv(IGM.DefaultCC); @@ -3704,8 +3704,6 @@ void IRGenSILFunction::visitReleaseValueInst(swift::ReleaseValueInst *i) { void IRGenSILFunction::visitReleaseValueAddrInst( swift::ReleaseValueAddrInst *i) { - assert(i->getAtomicity() == RefCountingInst::Atomicity::Atomic && - "Non atomic retains are not supported"); SILValue operandValue = i->getOperand(); Address addr = getLoweredAddress(operandValue); SILType addrTy = operandValue->getType(); @@ -3713,7 +3711,8 @@ void IRGenSILFunction::visitReleaseValueAddrInst( llvm::Type *llvmType = addr.getAddress()->getType(); const TypeInfo &addrTI = getTypeInfo(addrTy); auto *outlinedF = IGM.getOrCreateReleaseFunction( - addrTI, objectT, llvmType); + addrTI, objectT, llvmType, i->isAtomic() ? irgen::Atomicity::Atomic + : irgen::Atomicity::NonAtomic); llvm::Value *args[] = {addr.getAddress()}; llvm::CallInst *call = Builder.CreateCall(outlinedF, args); call->setCallingConv(IGM.DefaultCC); diff --git a/lib/IRGen/Outlining.cpp b/lib/IRGen/Outlining.cpp index 68f2d171732b2..82012dba2c5d4 100644 --- a/lib/IRGen/Outlining.cpp +++ b/lib/IRGen/Outlining.cpp @@ -399,7 +399,8 @@ llvm::Constant *IRGenModule::getOrCreateOutlinedDestroyFunction( llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti, SILType t, - llvm::Type *llvmType) { + llvm::Type *llvmType, + irgen::Atomicity atomicity) { auto *loadableTI = cast(&ti); IRGenMangler mangler; auto manglingBits = @@ -415,7 +416,7 @@ llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti, Explosion loaded; loadableTI->loadAsTake(IGF, addr, loaded); Explosion out; - loadableTI->copy(IGF, loaded, out, irgen::Atomicity::Atomic); + loadableTI->copy(IGF, loaded, out, atomicity); (void)out.claimAll(); IGF.Builder.CreateRet(addr.getAddress()); }, @@ -425,7 +426,8 @@ llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti, llvm::Constant * IRGenModule::getOrCreateReleaseFunction(const TypeInfo &ti, SILType t, - llvm::Type *llvmType) { + llvm::Type *llvmType, + irgen::Atomicity atomicity) { auto *loadableTI = cast(&ti); IRGenMangler mangler; auto manglingBits = @@ -440,7 +442,7 @@ IRGenModule::getOrCreateReleaseFunction(const TypeInfo &ti, Address addr(&*it++, loadableTI->getFixedAlignment()); Explosion loaded; loadableTI->loadAsTake(IGF, addr, loaded); - loadableTI->consume(IGF, loaded, irgen::Atomicity::Atomic); + loadableTI->consume(IGF, loaded, atomicity); IGF.Builder.CreateRet(addr.getAddress()); }, true /*setIsNoInline*/); From d82470a07d30b87fab5856d0c5055bd388fd3423 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 31 Aug 2020 14:15:33 -0700 Subject: [PATCH 475/663] [ownership] Merge regularUsers and implicitRegularUsers into just "regularUsers". When bringing up ownership I thought that it might be useful to distinguish "normal users" that just require liveness and are real transitive users vs implicit users that require liveness (I provide a constrasting example below). Turns out this distinction did not provide any benefit, so I am ripping it out so I can refactor this code to be used in other parts of the compiler where we only want a single array of "normal users". This is just a pure refactor. NFCI. -------------------------------------------------------------------------------- An example of the former would be an apply that uses an owned value as a guaranteed parameter: ``` bb0(%0 : @owned $Klass): apply %func(%0) : $@convention(thin) (@guaranteed $Klass) -> () ``` while an example of the latter is an end_apply of a coroutine that takes an owned value as a guaranteed parameter: ``` bb0(%0 : @owned $Klass): (%result, %token) = begin_apply %func(%0) ... end_apply %token destroy_value %0 ``` In the latter, we can not move the destroy_value past the end_apply. --- lib/SIL/Verifier/SILOwnershipVerifier.cpp | 36 +++++++---------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/lib/SIL/Verifier/SILOwnershipVerifier.cpp b/lib/SIL/Verifier/SILOwnershipVerifier.cpp index 7e48a583a39db..8490e003d920a 100644 --- a/lib/SIL/Verifier/SILOwnershipVerifier.cpp +++ b/lib/SIL/Verifier/SILOwnershipVerifier.cpp @@ -99,14 +99,6 @@ class SILValueOwnershipChecker { /// is successful. SmallVector regularUsers; - /// The list of implicit non lifetime ending users that we found. This - /// consists of instructions like end_borrow that end a scoped lifetime. We - /// must treat those as regular uses and ensure that our value is not - /// destroyed while that sub-scope is valid. - /// - /// TODO: Rename to SubBorrowScopeUsers? - SmallVector implicitRegularUsers; - /// The set of blocks that we have visited. SmallPtrSetImpl &visitedBlocks; @@ -133,13 +125,10 @@ class SILValueOwnershipChecker { bool isCompatibleDefUse(Operand *op, ValueOwnershipKind ownershipKind); bool gatherUsers(SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl ®ularUsers, - SmallVectorImpl &implicitRegularUsers); + SmallVectorImpl ®ularUsers); - bool - gatherNonGuaranteedUsers(SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl ®ularUsers, - SmallVectorImpl &implicitRegularUsers); + bool gatherNonGuaranteedUsers(SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl ®ularUsers); bool checkValueWithoutLifetimeEndingUses(); @@ -169,7 +158,6 @@ bool SILValueOwnershipChecker::check() { llvm::copy(lifetimeEndingUsers, std::back_inserter(allLifetimeEndingUsers)); SmallVector allRegularUsers; llvm::copy(regularUsers, std::back_inserter(allRegularUsers)); - llvm::copy(implicitRegularUsers, std::back_inserter(allRegularUsers)); LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); auto linearLifetimeResult = checker.checkValue(value, allLifetimeEndingUsers, @@ -223,8 +211,7 @@ bool SILValueOwnershipChecker::isCompatibleDefUse( bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl &nonLifetimeEndingUsers, - SmallVectorImpl &implicitRegularUsers) { + SmallVectorImpl &nonLifetimeEndingUsers) { bool foundError = false; auto ownershipKind = value.getOwnershipKind(); @@ -289,7 +276,7 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( }); }; foundError |= - initialScopedOperand->getImplicitUses(implicitRegularUsers, &error); + initialScopedOperand->getImplicitUses(nonLifetimeEndingUsers, &error); } return foundError; @@ -297,16 +284,15 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( bool SILValueOwnershipChecker::gatherUsers( SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl &nonLifetimeEndingUsers, - SmallVectorImpl &implicitRegularUsers) { + SmallVectorImpl &nonLifetimeEndingUsers) { // See if Value is guaranteed. If we are guaranteed and not forwarding, then // we need to look through subobject uses for more uses. Otherwise, if we are // forwarding, we do not create any lifetime ending users/non lifetime ending // users since we verify against our base. if (value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) { - return !gatherNonGuaranteedUsers( - lifetimeEndingUsers, nonLifetimeEndingUsers, implicitRegularUsers); + return !gatherNonGuaranteedUsers(lifetimeEndingUsers, + nonLifetimeEndingUsers); } // Ok, we have a value with guarantee ownership. Before we continue, check if @@ -387,7 +373,7 @@ bool SILValueOwnershipChecker::gatherUsers( }); }; foundError |= - scopedOperand->getImplicitUses(implicitRegularUsers, &onError); + scopedOperand->getImplicitUses(nonLifetimeEndingUsers, &onError); } // Next see if our use is an interior pointer operand. If we have an @@ -404,7 +390,7 @@ bool SILValueOwnershipChecker::gatherUsers( }); }; foundError |= interiorPointerOperand->getImplicitUses( - implicitRegularUsers, &onError); + nonLifetimeEndingUsers, &onError); } // Finally add the op to the non lifetime ending user list. @@ -621,7 +607,7 @@ bool SILValueOwnershipChecker::checkUses() { // 1. Verify that none of the uses are in the same block. This would be an // overconsume so in this case we assert. // 2. Verify that the uses are compatible with our ownership convention. - if (!gatherUsers(lifetimeEndingUsers, regularUsers, implicitRegularUsers)) { + if (!gatherUsers(lifetimeEndingUsers, regularUsers)) { // Silently return false if this fails. // // If the user pass in a ErrorBehaviorKind that will assert, we From 80a0f3eeb1fa5a8e678d41be2e2f587d2a1a98c3 Mon Sep 17 00:00:00 2001 From: Julian Lettner Date: Mon, 31 Aug 2020 14:59:26 -0700 Subject: [PATCH 476/663] [Sanitizer] Add smoke test for report symbolication (#33656) Add a test that checks symbolication for out-of-process and in-process symbolication for both Apple platforms and Linux. Note that there already exist tests in the compiler-rt test suite that check report symbolication. The purpose of this test is to have simple smoke tests for Swift, and specifically Swift demangling. rdar://62753845 Co-authored-by: Julian Lettner --- test/Sanitizers/symbolication-linux.swift | 35 +++++++++++++++++++++++ test/Sanitizers/symbolication.swift | 33 +++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 test/Sanitizers/symbolication-linux.swift create mode 100644 test/Sanitizers/symbolication.swift diff --git a/test/Sanitizers/symbolication-linux.swift b/test/Sanitizers/symbolication-linux.swift new file mode 100644 index 0000000000000..8e1827aa737c7 --- /dev/null +++ b/test/Sanitizers/symbolication-linux.swift @@ -0,0 +1,35 @@ +// RUN: %target-build-swift %s -sanitize=address -g -target %sanitizers-target-triple -o %t +// RUN: env %env-ASAN_OPTIONS=abort_on_error=0 not %target-run %t 2>&1 | %swift-demangle | %FileCheck %s -check-prefix=OOP +// In-process symbolication doesn't work on Linux (yet) +// XXX: env %env-ASAN_OPTIONS=abort_on_error=0,external_symbolizer_path= not %target-run %t 2>&1 | %swift-demangle | %FileCheck %s -check-prefix=IP +// REQUIRES: executable_test +// REQUIRES: asan_runtime +// REQUIRES: OS=linux-gnu + +// Check that Sanitizer reports are properly symbolicated on Linux, both +// out-of-process (via `llvm-symbolizer`) and when falling back to in-process +// symbolication. Note that `llvm-symbolizer` does not demangle Swift symbol +// names, so we use `swift demangle`. + +func foo() { + let x = UnsafeMutablePointer.allocate(capacity: 1) + x.deallocate() + print(x.pointee) +} + +func bar() { + foo() +} + +bar() + + +// Out-of-process +// OOP: #0 0x{{[0-9a-f]+}} in main.foo() -> () {{.*}}symbolication-linux.swift:[[@LINE-11]] +// OOP-NEXT: #1 0x{{[0-9a-f]+}} in main.bar() -> () {{.*}}symbolication-linux.swift:[[@LINE-8]] +// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main {{.*}}symbolication-linux.swift:[[@LINE-6]] + +// In-process +// IP: #0 0x{{[0-9a-f]+}} in main.foo() -> ()+0x +// IP-NEXT: #1 0x{{[0-9a-f]+}} in main.bar() -> ()+0x +// IP-NEXT: #2 0x{{[0-9a-f]+}} in main+0x diff --git a/test/Sanitizers/symbolication.swift b/test/Sanitizers/symbolication.swift new file mode 100644 index 0000000000000..9f95a4f8c033a --- /dev/null +++ b/test/Sanitizers/symbolication.swift @@ -0,0 +1,33 @@ +// RUN: %target-build-swift %s -sanitize=address -g -target %sanitizers-target-triple -o %t +// RUN: env %env-ASAN_OPTIONS=abort_on_error=0 not %target-run %t 2>&1 | %FileCheck %s -check-prefix=OOP +// RUN: env %env-ASAN_OPTIONS=abort_on_error=0,external_symbolizer_path= not %target-run %t 2>&1 | %FileCheck %s -check-prefix=IP +// REQUIRES: executable_test +// REQUIRES: asan_runtime +// REQUIRES: VENDOR=apple + +// Check that Sanitizer reports are properly symbolicated on Apple platforms, +// both out-of-process (via `atos`) and when falling back to in-process +// symbolication. Note that `atos` also demangles Swift symbol names. + +func foo() { + let x = UnsafeMutablePointer.allocate(capacity: 1) + x.deallocate() + print(x.pointee) +} + +func bar() { + foo() +} + +bar() + + +// Out-of-process +// OOP: #0 0x{{[0-9a-f]+}} in foo() symbolication.swift:[[@LINE-11]] +// OOP-NEXT: #1 0x{{[0-9a-f]+}} in bar() symbolication.swift:[[@LINE-8]] +// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main symbolication.swift:[[@LINE-6]] + +// In-process +// IP: #0 0x{{[0-9a-f]+}} in main.foo() -> ()+0x +// IP-NEXT: #1 0x{{[0-9a-f]+}} in main.bar() -> ()+0x +// IP-NEXT: #2 0x{{[0-9a-f]+}} in main+0x From e6249576eafc39de27029596a7c163fcc82284ca Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 31 Aug 2020 18:20:22 -0400 Subject: [PATCH 477/663] DI: Rename testControlVariable() to testControlVariableBit() --- .../Mandatory/DefiniteInitialization.cpp | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index ab7a60c936c07..da7370b39ec39 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -2186,12 +2186,12 @@ static void updateControlVariable(SILLocation Loc, } /// Test a bit in the control variable at the current insertion point. -static SILValue testControlVariable(SILLocation Loc, - unsigned Elt, - SILValue ControlVariableAddr, - Identifier &ShiftRightFn, - Identifier &TruncateFn, - SILBuilder &B) { +static SILValue testControlVariableBit(SILLocation Loc, + unsigned Elt, + SILValue ControlVariableAddr, + Identifier &ShiftRightFn, + Identifier &TruncateFn, + SILBuilder &B) { SILValue ControlVariable = B.createLoad(Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial); @@ -2324,9 +2324,9 @@ SILValue LifetimeChecker::handleConditionalInitAssign() { // initialization. for (unsigned Elt = Use.FirstElement, e = Elt+Use.NumElements; Elt != e; ++Elt) { - auto CondVal = testControlVariable(Loc, Elt, ControlVariableAddr, - ShiftRightFn, TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, Elt, ControlVariableAddr, + ShiftRightFn, TruncateFn, + B); SILBasicBlock *TrueBB, *FalseBB, *ContBB; InsertCFGDiamond(CondVal, Loc, B, @@ -2465,9 +2465,9 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // Insert a load of the liveness bitmask and split the CFG into a diamond // right before the destroy_addr, if we haven't already loaded it. - auto CondVal = testControlVariable(Loc, Elt, ControlVariableAddr, - ShiftRightFn, TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, Elt, ControlVariableAddr, + ShiftRightFn, TruncateFn, + B); SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock; @@ -2486,11 +2486,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // depending on if the self box was initialized or not. auto emitReleaseOfSelfWhenNotConsumed = [&](SILLocation Loc, SILInstruction *Release) { - auto CondVal = testControlVariable(Loc, SelfInitializedElt, - ControlVariableAddr, - ShiftRightFn, - TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, SelfInitializedElt, + ControlVariableAddr, + ShiftRightFn, + TruncateFn, + B); SILBasicBlock *ReleaseBlock, *ConsumedBlock, *ContBlock; @@ -2573,11 +2573,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // self.init or super.init may or may not have been called. // We have not yet stored 'self' into the box. - auto CondVal = testControlVariable(Loc, SuperInitElt, - ControlVariableAddr, - ShiftRightFn, - TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, SuperInitElt, + ControlVariableAddr, + ShiftRightFn, + TruncateFn, + B); SILBasicBlock *ConsumedBlock, *DeallocBlock, *ContBlock; @@ -2607,11 +2607,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // self.init or super.init may or may not have been called. // We may or may have stored 'self' into the box. - auto CondVal = testControlVariable(Loc, SuperInitElt, - ControlVariableAddr, - ShiftRightFn, - TruncateFn, - B); + auto CondVal = testControlVariableBit(Loc, SuperInitElt, + ControlVariableAddr, + ShiftRightFn, + TruncateFn, + B); SILBasicBlock *LiveBlock, *DeallocBlock, *ContBlock; From 7f7530f4e77bcba47ab96bc19c89fd549ec65e94 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 31 Aug 2020 16:11:55 -0700 Subject: [PATCH 478/663] [Statement checking] Fix "old" fallthrough source. Fallthrough statement sources have always been incorrectly computed when there are nested switch statements. The recent refactoring to switch fallthrough source/destination computation over to ASTScope fixed the computation. Amusingly, the assertion that ensures that the old and new implementations produce the same result fires on these cases, but it's the old implementation that's wrong. Fix up the old implementation so the assertion does not trigger. The new test case crashes in Swift 5.3 and earlier, asserts prior to this change. Fixes rdar://problem/67704651. --- lib/Sema/TypeCheckStmt.cpp | 6 +++++- test/SILGen/switch_fallthrough.swift | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 102b11d5fed94..1aec917a56eaf 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -725,12 +725,16 @@ class StmtChecker : public StmtVisitor { struct AddSwitchNest { StmtChecker &SC; + CaseStmt *OuterFallthroughSource; CaseStmt *OuterFallthroughDest; - AddSwitchNest(StmtChecker &SC) : SC(SC), + AddSwitchNest(StmtChecker &SC) + : SC(SC), + OuterFallthroughSource(SC.FallthroughSource), OuterFallthroughDest(SC.FallthroughDest) { } ~AddSwitchNest() { + SC.FallthroughSource = OuterFallthroughSource; SC.FallthroughDest = OuterFallthroughDest; } }; diff --git a/test/SILGen/switch_fallthrough.swift b/test/SILGen/switch_fallthrough.swift index 77b5c5cf3e626..4be37a1adf6c4 100644 --- a/test/SILGen/switch_fallthrough.swift +++ b/test/SILGen/switch_fallthrough.swift @@ -165,3 +165,20 @@ func test5() { e() } +// rdar://problem/67704651 - crash due to nested fallthrough +func testNestedFallthrough(x: (Int, String), y: (Int, Int)) { + switch x { + case (17, let s): + switch y { + case (42, let i): + print("the answer") + default: + print("nope") + } + fallthrough + case (42, let s): + print("42 and \(s)") + default: + print("done") + } +} From 82c43a8ac75e82f080b9bc157e26af5a16b33f72 Mon Sep 17 00:00:00 2001 From: tbkka Date: Mon, 31 Aug 2020 17:52:22 -0700 Subject: [PATCH 479/663] [Dynamic Casting] Allow casts to "more optional" types (#33684) Generally, casting consistency demands that we be able to extract anything from an existential that can be put into that existential. (Which is why the casting spec requires that casting permit arbitrary injection and projection of optionals.) This particular diagnostic prevented optionals from being projected back out of existentials: let i: Int? let a: Any = i // Inject Int? into Any // Error prevents projecting Int? back out of Any a as? Int? This also broke certain uses of Mirror (weak variables get reflected as optionals stored in Any existentials). --- include/swift/AST/DiagnosticsSema.def | 3 --- lib/Sema/CSApply.cpp | 9 +++------ lib/Sema/TypeCheckConstraints.cpp | 17 +++++------------ test/Constraints/casts.swift | 6 +++--- test/Constraints/optional.swift | 10 ++++++---- test/expr/cast/as_coerce.swift | 6 ++++-- 6 files changed, 21 insertions(+), 30 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 9d36c35bc7c80..3ee614d2095de 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1045,9 +1045,6 @@ WARNING(downcast_to_unrelated,none, "cast from %0 to unrelated type %1 always fails", (Type, Type)) NOTE(downcast_to_unrelated_fixit,none, "did you mean to call %0 with '()'?", (Identifier)) -ERROR(downcast_to_more_optional,none, - "cannot downcast from %0 to a more optional type %1", - (Type, Type)) ERROR(optional_chain_noop,none, "optional chain has no effect, expression already produces %0", (Type)) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index d04154edcd748..831add9e6c599 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3790,17 +3790,14 @@ namespace { }; // There's nothing special to do if the operand isn't optional - // and we don't need any bridging. - if (srcOptionals.empty()) { + // (or is insufficiently optional) and we don't need any bridging. + if (srcOptionals.empty() + || (srcOptionals.size() < destOptionals.size() - destExtraOptionals)) { Expr *result = buildInnerOperation(subExpr, finalResultType); if (!result) return nullptr; return addFinalOptionalInjections(result); } - // The result type (without the final optional) is a subtype of - // the operand type, so it will never have a higher depth. - assert(destOptionals.size() - destExtraOptionals <= srcOptionals.size()); - // The outermost N levels of optionals on the operand must all // be present or the cast fails. The innermost M levels of // optionals on the operand are reflected in the requested diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index f0226a6d094e8..32f6087c9fb19 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -3167,21 +3167,14 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, return CheckedCastKind::ValueCast; }; - // Strip optional wrappers off of the destination type in sync with - // stripping them off the origin type. + // TODO: Explore optionals using the same strategy used by the + // runtime. + // For now, if the target is more optional than the source, + // just defer it out for the runtime to handle. while (auto toValueType = toType->getOptionalObjectType()) { - // Complain if we're trying to increase optionality, e.g. - // casting an NSObject? to an NSString??. That's not a subtype - // relationship. auto fromValueType = fromType->getOptionalObjectType(); if (!fromValueType) { - if (!suppressDiagnostics) { - diags.diagnose(diagLoc, diag::downcast_to_more_optional, - origFromType, origToType) - .highlight(diagFromRange) - .highlight(diagToRange); - } - return CheckedCastKind::Unresolved; + return CheckedCastKind::ValueCast; } toType = toValueType; diff --git a/test/Constraints/casts.swift b/test/Constraints/casts.swift index 0ea574583a5b8..c63dc7354d225 100644 --- a/test/Constraints/casts.swift +++ b/test/Constraints/casts.swift @@ -252,11 +252,11 @@ func test_coercions_with_overloaded_operator(str: String, optStr: String?, veryO _ = (str ?? "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} _ = (optStr ?? "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} - _ = (optStr ?? "") as Int? // expected-error {{cannot convert value of type 'String' to type 'Int?' in coercion}} + _ = (optStr ?? "") as Int? // expected-error {{'String' is not convertible to 'Int?'; did you mean to use 'as!' to force downcast?}} _ = (str ^^^ "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} _ = (optStr ^^^ "") as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}} - _ = (optStr ^^^ "") as Int? // expected-error {{cannot convert value of type 'String' to type 'Int?' in coercion}} + _ = (optStr ^^^ "") as Int? // expected-error {{'String' is not convertible to 'Int?'; did you mean to use 'as!' to force downcast?}} _ = ([] ?? []) as String // expected-error {{cannot convert value of type '[Any]' to type 'String' in coercion}} _ = ([""] ?? []) as [Int: Int] // expected-error {{cannot convert value of type '[String]' to type '[Int : Int]' in coercion}} @@ -290,7 +290,7 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin // expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}} _ = dict as [String: String] // expected-error {{cannot convert value of type '[String : Int]' to type '[String : String]' in coercion}} // expected-note@-1 {{arguments to generic parameter 'Value' ('Int' and 'String') are expected to be equal}} - _ = dict as [String: String]? // expected-error {{cannot convert value of type '[String : Int]' to type '[String : String]?' in coercion}} + _ = dict as [String: String]? // expected-error {{'[String : Int]' is not convertible to '[String : String]?'; did you mean to use 'as!' to force downcast?}} _ = (dict as [String: Int]?) as [String: Int] // expected-error {{value of optional type '[String : Int]?' must be unwrapped to a value of type '[String : Int]'}} // expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} // expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} diff --git a/test/Constraints/optional.swift b/test/Constraints/optional.swift index 246abdbe22491..352a8bee83eff 100644 --- a/test/Constraints/optional.swift +++ b/test/Constraints/optional.swift @@ -64,15 +64,17 @@ func test5() -> Int? { } func test6(_ x : T) { - // FIXME: this code should work; T could be Int? or Int?? - // or something like that at runtime. rdar://16374053 - _ = x as? Int? // expected-error {{cannot downcast from 'T' to a more optional type 'Int?'}} + _ = x as? Int? // Okay. We know nothing about T, so cannot judge. } class B : A { } func test7(_ x : A) { - _ = x as? B? // expected-error{{cannot downcast from 'A' to a more optional type 'B?'}} + _ = x as? B? // Okay: Injecting into an Optional +} + +func test7a(_ x : B) { + _ = x as? A // expected-warning{{conditional cast from 'B' to 'A' always succeeds}} } func test8(_ x : AnyObject?) { diff --git a/test/expr/cast/as_coerce.swift b/test/expr/cast/as_coerce.swift index 962c656322ca1..165d7b9eebafb 100644 --- a/test/expr/cast/as_coerce.swift +++ b/test/expr/cast/as_coerce.swift @@ -68,14 +68,16 @@ class C5 {} var c: AnyObject = C3() -if let castX = c as! C4? {} // expected-error {{cannot downcast from 'AnyObject' to a more optional type 'C4?'}} +// XXX TODO: Constant-folding should generate an error about 'C3' not being convertible to 'C4' +//if let castX = c as! C4? {} -// Only suggest replacing 'as' with 'as!' if it would fix the error. +// XXX TODO: Only suggest replacing 'as' with 'as!' if it would fix the error. C3() as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to use 'as!' to force downcast?}} {{6-8=as!}} C3() as C5 // expected-error {{cannot convert value of type 'C3' to type 'C5' in coercion}} // Diagnostic shouldn't include @lvalue in type of c3. var c3 = C3() +// XXX TODO: This should not suggest `as!` c3 as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to use 'as!' to force downcast?}} {{4-6=as!}} // Various incorrect diagnostics for explicit type conversions From d26f336b0b59084713caff67f9a961f5b8e179f7 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sat, 29 Aug 2020 21:30:02 -0700 Subject: [PATCH 480/663] [semantic-arc] Split out copy_value optimizations (except phi elimination) into its own file. --- lib/SILOptimizer/SemanticARC/CMakeLists.txt | 3 +- .../SemanticARC/CopyValueOpts.cpp | 478 ++++++++++++++++++ .../SemanticARC/SemanticARCOpts.cpp | 443 ---------------- 3 files changed, 480 insertions(+), 444 deletions(-) create mode 100644 lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt index 2244810281658..f2ebe23343f96 100644 --- a/lib/SILOptimizer/SemanticARC/CMakeLists.txt +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -2,4 +2,5 @@ target_sources(swiftSILOptimizer PRIVATE SemanticARCOpts.cpp OwnershipLiveRange.cpp LoadCopyToLoadBorrowOpt.cpp - BorrowScopeOpts.cpp) + BorrowScopeOpts.cpp + CopyValueOpts.cpp) diff --git a/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp new file mode 100644 index 0000000000000..4d2ba9134d731 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp @@ -0,0 +1,478 @@ +//===--- CopyValueOpts.cpp ------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Contains optimizations that eliminate redundant copy values. +/// +//===----------------------------------------------------------------------===// + +#include "OwnershipPhiOperand.h" +#include "SemanticARCOptVisitor.h" + +using namespace swift; +using namespace swift::semanticarc; + +//===----------------------------------------------------------------------===// +// Guaranteed Copy Value Optimization +//===----------------------------------------------------------------------===// + +// Eliminate a copy of a borrowed value, if: +// +// 1. All of the copies users do not consume the copy (and thus can accept a +// borrowed value instead). +// 2. The copies's non-destroy_value users are strictly contained within the +// scope of the borrowed value. +// +// Example: +// +// %0 = @guaranteed (argument or instruction) +// %1 = copy_value %0 +// apply %f(%1) : $@convention(thin) (@guaranteed ...) ... +// other_non_consuming_use %1 +// destroy_value %1 +// end_borrow %0 (if an instruction) +// +// => +// +// %0 = @guaranteed (argument or instruction) +// apply %f(%0) : $@convention(thin) (@guaranteed ...) ... +// other_non_consuming_use %0 +// end_borrow %0 (if an instruction) +// +// NOTE: This means that the destroy_value technically can be after the +// end_borrow. In practice, this will not be the case but we use this to avoid +// having to reason about the ordering of the end_borrow and destroy_value. +// +// NOTE: Today we only perform this for guaranteed parameters since this enables +// us to avoid doing the linear lifetime check to make sure that all destroys +// are within the borrow scope. +// +// TODO: This needs a better name. +bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization( + CopyValueInst *cvi) { + // For now, do not run this optimization. This is just to be careful. + if (onlyGuaranteedOpts) + return false; + + SmallVector borrowScopeIntroducers; + + // Find all borrow introducers for our copy operand. If we are unable to find + // all of the reproducers (due to pattern matching failure), conservatively + // return false. We can not optimize. + // + // NOTE: We can get multiple introducers if our copy_value's operand + // value runs through a phi or an aggregate forming instruction. + if (!getAllBorrowIntroducingValues(cvi->getOperand(), borrowScopeIntroducers)) + return false; + + // Then go over all of our uses and see if the value returned by our copy + // value forms a dead live range or a live range that would be dead if it was + // not consumed by phi nodes. If we do not have such a live range, there must + // be some consuming use that we either do not understand is /actually/ + // forwarding or a user that truly represents a necessary consume of the value + // (e.x. storing into memory). + OwnershipLiveRange lr(cvi); + auto hasUnknownConsumingUseState = + lr.hasUnknownConsumingUse(assumingAtFixedPoint); + if (hasUnknownConsumingUseState == + OwnershipLiveRange::HasConsumingUse_t::Yes) { + return false; + } + + // Next check if we do not have any destroys of our copy_value and are + // processing a local borrow scope. In such a case, due to the way we ignore + // dead end blocks, we may eliminate the copy_value, creating a use of the + // borrowed value after the end_borrow. To avoid this, in such cases we + // bail. In contrast, a non-local borrow scope does not have any end scope + // instructions, implying we can avoid this hazard and still optimize in such + // a case. + // + // DISCUSSION: Consider the following SIL: + // + // ``` + // %1 = begin_borrow %0 : $KlassPair (1) + // %2 = struct_extract %1 : $KlassPair, #KlassPair.firstKlass + // %3 = copy_value %2 : $Klass + // ... + // end_borrow %1 : $LintCommand (2) + // cond_br ..., bb1, bb2 + // + // ... + // + // bbN: + // // Never return type implies dead end block. + // apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> Never (3) + // unreachable + // ``` + // + // For simplicity, note that if bbN post-dominates %3, given that when we + // compute linear lifetime errors we ignore dead end blocks, we would not + // register that the copy_values only use is outside of the begin_borrow + // region defined by (1), (2) and thus would eliminate the copy. This would + // result in %2 being used by %f, causing the linear lifetime checker to + // error. + // + // Naively one may assume that the solution to this is to just check if %3 has + // /any/ destroy_values at all and if it doesn't have any reachable + // destroy_values, then we are in this case. But is this correct in + // general. We prove this below: + // + // The only paths along which the copy_value can not be destroyed or consumed + // is along paths to dead end blocks. Trivially, we know that such a dead end + // block, can not be reachable from the end_borrow since by their nature dead + // end blocks end in unreachables. + // + // So we know that we can only run into this bug if we have a dead end block + // reachable from the end_borrow, meaning that the bug can not occur if we + // branch before the end_borrow since in that case, the borrow scope would + // last over the dead end block's no return meaning that we will not use the + // borrowed value after its lifetime is ended by the end_borrow. + // + // With that in hand, we note again that if we have exactly one consumed, + // destroy_value /after/ the end_borrow we will not optimize here. This means + // that this bug can only occur if the copy_value is only post-dominated by + // dead end blocks that use the value in a non-consuming way. + // + // TODO: There may be some way of sinking this into the loop below. + bool haveAnyLocalScopes = + llvm::any_of(borrowScopeIntroducers, [](BorrowedValue borrowScope) { + return borrowScope.isLocalScope(); + }); + + auto destroys = lr.getDestroyingUses(); + if (destroys.empty() && haveAnyLocalScopes) { + return false; + } + + // If we reached this point, then we know that all of our users can accept a + // guaranteed value and our owned value is destroyed only by a set of + // destroy_values. Check if: + // + // 1. All of our destroys are joint post-dominated by our end borrow scope + // set. If they do not, then the copy_value is lifetime extending the + // guaranteed value, we can not eliminate it. + // + // 2. If all of our destroy_values are dead end. In such a case, the linear + // lifetime checker will not perform any checks since it assumes that dead + // end destroys can be ignored. Since we are going to end the program + // anyways, we want to be conservative here and optimize only if we do not + // need to insert an end_borrow since all of our borrow introducers are + // non-local scopes. + { + bool foundNonDeadEnd = false; + for (auto *d : destroys) { + foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(d->getParentBlock()); + } + if (!foundNonDeadEnd && haveAnyLocalScopes) + return false; + SmallVector scratchSpace; + SmallPtrSet visitedBlocks; + if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { + return !borrowScope.areUsesWithinScope(lr.getAllConsumingUses(), + scratchSpace, visitedBlocks, + getDeadEndBlocks()); + })) { + return false; + } + } + + // Otherwise, we know that our copy_value/destroy_values are all completely + // within the guaranteed value scope. So we /could/ optimize it. Now check if + // we were truly dead or if we are dead if we can eliminate phi arg uses. If + // we need to handle the phi arg uses, we bail. After we reach a fixed point, + // we will try to eliminate this value then if we can find a complete set of + // all incoming values to our phi argument. + if (hasUnknownConsumingUseState == + OwnershipLiveRange::HasConsumingUse_t::YesButAllPhiArgs) { + auto opPhi = *OwnershipPhiOperand::get(lr.getSingleUnknownConsumingUse()); + SmallVector scratchSpace; + SmallPtrSet visitedBlocks; + + bool canOptimizePhi = opPhi.visitResults([&](SILValue value) { + SWIFT_DEFER { + scratchSpace.clear(); + visitedBlocks.clear(); + }; + + OwnershipLiveRange phiArgLR(value); + if (bool(phiArgLR.hasUnknownConsumingUse())) { + return false; + } + + if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { + return !borrowScope.areUsesWithinScope( + phiArgLR.getAllConsumingUses(), scratchSpace, visitedBlocks, + getDeadEndBlocks()); + })) { + return false; + } + + return true; + }); + + if (canOptimizePhi) { + opPhi.visitResults([&](SILValue value) { + joinedOwnedIntroducerToConsumedOperands.insert(value, + opPhi.getOperand()); + return true; + }); + } + + return false; + } + + // Otherwise, our copy must truly not be needed, o RAUW and convert to + // guaranteed! + std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), getCallbacks()); + return true; +} + +//===----------------------------------------------------------------------===// +// Trivial Live Range Elimination +//===----------------------------------------------------------------------===// + +/// If cvi only has destroy value users, then cvi is a dead live range. Lets +/// eliminate all such dead live ranges. +bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue( + CopyValueInst *cvi) { + // This is a cheap optimization generally. + + // See if we are lucky and have a simple case. + if (auto *op = cvi->getSingleUse()) { + if (auto *dvi = dyn_cast(op->getUser())) { + eraseInstruction(dvi); + eraseInstructionAndAddOperandsToWorklist(cvi); + return true; + } + } + + // If all of our copy_value users are destroy_value, zap all of the + // instructions. We begin by performing that check and gathering up our + // destroy_value. + SmallVector destroys; + if (!all_of(cvi->getUses(), [&](Operand *op) { + auto *dvi = dyn_cast(op->getUser()); + if (!dvi) + return false; + + // Stash dvi in destroys so we can easily eliminate it later. + destroys.push_back(dvi); + return true; + })) { + return false; + } + + // Now that we have a truly dead live range copy value, eliminate it! + while (!destroys.empty()) { + eraseInstruction(destroys.pop_back_val()); + } + eraseInstructionAndAddOperandsToWorklist(cvi); + return true; +} + +//===----------------------------------------------------------------------===// +// Live Range Joining +//===----------------------------------------------------------------------===// + +// Handle simple checking where we do not need to form live ranges and visit a +// bunch of instructions. +static bool canSafelyJoinSimpleRange(SILValue cviOperand, + DestroyValueInst *cviOperandDestroy, + CopyValueInst *cvi) { + // We only handle cases where our copy_value has a single consuming use that + // is not a forwarding use. We need to use the LiveRange functionality to + // guarantee correctness in the presence of forwarding uses. + // + // NOTE: This use may be any type of consuming use and may not be a + // destroy_value. + auto *cviConsumer = cvi->getSingleConsumingUse(); + if (!cviConsumer || isOwnedForwardingInstruction(cviConsumer->getUser())) { + return false; + } + + // Ok, we may be able to eliminate this. The main thing we need to be careful + // of here is that if the destroy_value is /after/ the consuming use of the + // operand of copy_value, we may have normal uses of the copy_value's operand + // that would become use-after-frees since we would be shrinking the lifetime + // of the object potentially. Consider the following SIL: + // + // %0 = ... + // %1 = copy_value %0 + // apply %cviConsumer(%1) + // apply %guaranteedUser(%0) + // destroy_value %0 + // + // Easily, if we were to eliminate the copy_value, destroy_value, the object's + // lifetime could potentially be shrunk before guaranteedUser is executed, + // causing guaranteedUser to be a use-after-free. + // + // As an extra wrinkle, until all interior pointer constructs (e.x.: + // project_box) are guaranteed to be guaranted by a begin_borrow, we can not + // in general safely shrink lifetimes. So even if we think we can prove that + // all non-consuming uses of %0 are before apply %cviConsumer, we may miss + // implicit uses that are not guarded yet by a begin_borrow, resulting in + // use-after-frees. + // + // With that in mind, we only handle cases today where we can prove that + // destroy_value is strictly before the consuming use of the operand. This + // guarantees that we are not shrinking the lifetime of the underlying object. + // + // First we handle the simple case: where the cviConsumer is a return inst. In + // such a case, we know for sure that cviConsumer post-dominates the + // destroy_value. + auto cviConsumerIter = cviConsumer->getUser()->getIterator(); + if (isa(cviConsumerIter)) { + return true; + } + + // Then see if our cviConsumer is in the same block as a return inst and the + // destroy_value is not. In that case, we know that the cviConsumer must + // post-dominate the destroy_value. + auto *cviConsumingBlock = cviConsumerIter->getParent(); + if (isa(cviConsumingBlock->getTerminator()) && + cviConsumingBlock != cviOperandDestroy->getParent()) { + return true; + } + + // Otherwise, we only support joining live ranges where the cvi and the cvi's + // operand's destroy are in the same block with the destroy_value of cvi + // operand needing to be strictly after the copy_value. This analysis can be + // made significantly stronger by using LiveRanges, but this is simple for + // now. + auto cviOperandDestroyIter = cviOperandDestroy->getIterator(); + if (cviConsumingBlock != cviOperandDestroyIter->getParent()) { + return false; + } + + // TODO: This should really be llvm::find, but for some reason, the templates + // do not match up given the current state of the iterators. This impl works + // in a pinch though. + return llvm::any_of( + llvm::make_range(cviOperandDestroyIter, + cviOperandDestroyIter->getParent()->end()), + [&](const SILInstruction &val) { return &*cviConsumerIter == &val; }); +} + +// # The Problem We Are Solving +// +// The main idea here is that we are trying to eliminate the simplest, easiest +// form of live range joining. Consider the following SIL: +// +// ``` +// %cviOperand = ... // @owned value +// %cvi = copy_value %cviOperand // copy of @owned value +// ... +// destroy_value %cviOperandDestroy // destruction of @owned value +// ... +// apply %consumingUser(%cvi) // destruction of copy of @owned value +// ``` +// +// We want to reduce reference count traffic by eliminating the middle +// copy/destroy yielding: +// +// ``` +// %cviOperand = ... // @owned value +// // *eliminated copy_value* +// ... +// // *eliminated destroy_value* +// ... +// apply %consumingUser(%cviOperand) // destruction of copy of @owned +// value +// ``` +// +// # Safety +// +// In order to do this safely, we need to take the union of the two objects +// lifetimes since we are only joining lifetimes. This ensures that we can rely +// on SILGen's correctness on inserting safe lifetimes. To keep this simple +// today we only optimize if the destroy_value and consuming user are in the +// same block and the consuming user is later in the block than the +// destroy_value. +// +// DISCUSSION: The reason why we do not shrink lifetimes today is that all +// interior pointers (e.x. project_box) are properly guarded by +// begin_borrow. Because of that we can not shrink lifetimes and instead rely on +// SILGen's correctness. +bool SemanticARCOptVisitor::tryJoiningCopyValueLiveRangeWithOperand( + CopyValueInst *cvi) { + // First do a quick check if our operand is owned. If it is not owned, we can + // not join live ranges. + SILValue operand = cvi->getOperand(); + if (operand.getOwnershipKind() != ValueOwnershipKind::Owned) { + return false; + } + + // Then check if our operand has a single destroy_value. If it does and that + // destroy_value is strictly before the consumer of our copy_value in the same + // block as the consumer of said copy_value then we can always join the live + // ranges. + // + // Example: + // + // ``` + // %1 = copy_value %0 + // ... + // destroy_value %0 + // apply %consumingUser(%1) + // ``` + // -> + // + // ``` + // apply %consumingUser(%0) + // ``` + // + // DISCUSSION: We need to ensure that the consuming use of the copy_value is + // strictly after the destroy_value to ensure that we do not shrink the live + // range of the operand if the operand has any normal uses beyond our copy + // value. Otherwise, we could have normal uses /after/ the consuming use of + // our copy_value. + if (auto *dvi = operand->getSingleConsumingUserOfType()) { + if (canSafelyJoinSimpleRange(operand, dvi, cvi)) { + eraseInstruction(dvi); + eraseAndRAUWSingleValueInstruction(cvi, operand); + return true; + } + } + + // Otherwise, we couldn't handle this case, so return false. + // + // NOTE: We would generally do a more complex analysis here to handle the more + // general case. That would most likely /not/ be a guaranteed optimization + // until we investigate/measure. + return false; +} + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) { + // If our copy value inst has only destroy_value users, it is a dead live + // range. Try to eliminate them. + if (eliminateDeadLiveRangeCopyValue(cvi)) { + return true; + } + + // Then see if copy_value operand's lifetime ends after our copy_value via a + // destroy_value. If so, we can join their lifetimes. + if (tryJoiningCopyValueLiveRangeWithOperand(cvi)) { + return true; + } + + // Then try to perform the guaranteed copy value optimization. + if (performGuaranteedCopyValueOptimization(cvi)) { + return true; + } + + return false; +} diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index 444cdc6d90b40..cc57de73f7c5c 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -376,449 +376,6 @@ bool SemanticARCOptVisitor::processWorklist() { return madeChange; } -//===----------------------------------------------------------------------===// -// CopyValue Optimizations Elimination -//===----------------------------------------------------------------------===// - -// Eliminate a copy of a borrowed value, if: -// -// 1. All of the copies users do not consume the copy (and thus can accept a -// borrowed value instead). -// 2. The copies's non-destroy_value users are strictly contained within the -// scope of the borrowed value. -// -// Example: -// -// %0 = @guaranteed (argument or instruction) -// %1 = copy_value %0 -// apply %f(%1) : $@convention(thin) (@guaranteed ...) ... -// other_non_consuming_use %1 -// destroy_value %1 -// end_borrow %0 (if an instruction) -// -// => -// -// %0 = @guaranteed (argument or instruction) -// apply %f(%0) : $@convention(thin) (@guaranteed ...) ... -// other_non_consuming_use %0 -// end_borrow %0 (if an instruction) -// -// NOTE: This means that the destroy_value technically can be after the -// end_borrow. In practice, this will not be the case but we use this to avoid -// having to reason about the ordering of the end_borrow and destroy_value. -// -// NOTE: Today we only perform this for guaranteed parameters since this enables -// us to avoid doing the linear lifetime check to make sure that all destroys -// are within the borrow scope. -// -// TODO: This needs a better name. -bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization( - CopyValueInst *cvi) { - // For now, do not run this optimization. This is just to be careful. - if (onlyGuaranteedOpts) - return false; - - SmallVector borrowScopeIntroducers; - - // Find all borrow introducers for our copy operand. If we are unable to find - // all of the reproducers (due to pattern matching failure), conservatively - // return false. We can not optimize. - // - // NOTE: We can get multiple introducers if our copy_value's operand - // value runs through a phi or an aggregate forming instruction. - if (!getAllBorrowIntroducingValues(cvi->getOperand(), borrowScopeIntroducers)) - return false; - - // Then go over all of our uses and see if the value returned by our copy - // value forms a dead live range or a live range that would be dead if it was - // not consumed by phi nodes. If we do not have such a live range, there must - // be some consuming use that we either do not understand is /actually/ - // forwarding or a user that truly represents a necessary consume of the value - // (e.x. storing into memory). - OwnershipLiveRange lr(cvi); - auto hasUnknownConsumingUseState = - lr.hasUnknownConsumingUse(assumingAtFixedPoint); - if (hasUnknownConsumingUseState == - OwnershipLiveRange::HasConsumingUse_t::Yes) { - return false; - } - - // Next check if we do not have any destroys of our copy_value and are - // processing a local borrow scope. In such a case, due to the way we ignore - // dead end blocks, we may eliminate the copy_value, creating a use of the - // borrowed value after the end_borrow. To avoid this, in such cases we - // bail. In contrast, a non-local borrow scope does not have any end scope - // instructions, implying we can avoid this hazard and still optimize in such - // a case. - // - // DISCUSSION: Consider the following SIL: - // - // ``` - // %1 = begin_borrow %0 : $KlassPair (1) - // %2 = struct_extract %1 : $KlassPair, #KlassPair.firstKlass - // %3 = copy_value %2 : $Klass - // ... - // end_borrow %1 : $LintCommand (2) - // cond_br ..., bb1, bb2 - // - // ... - // - // bbN: - // // Never return type implies dead end block. - // apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> Never (3) - // unreachable - // ``` - // - // For simplicity, note that if bbN post-dominates %3, given that when we - // compute linear lifetime errors we ignore dead end blocks, we would not - // register that the copy_values only use is outside of the begin_borrow - // region defined by (1), (2) and thus would eliminate the copy. This would - // result in %2 being used by %f, causing the linear lifetime checker to - // error. - // - // Naively one may assume that the solution to this is to just check if %3 has - // /any/ destroy_values at all and if it doesn't have any reachable - // destroy_values, then we are in this case. But is this correct in - // general. We prove this below: - // - // The only paths along which the copy_value can not be destroyed or consumed - // is along paths to dead end blocks. Trivially, we know that such a dead end - // block, can not be reachable from the end_borrow since by their nature dead - // end blocks end in unreachables. - // - // So we know that we can only run into this bug if we have a dead end block - // reachable from the end_borrow, meaning that the bug can not occur if we - // branch before the end_borrow since in that case, the borrow scope would - // last over the dead end block's no return meaning that we will not use the - // borrowed value after its lifetime is ended by the end_borrow. - // - // With that in hand, we note again that if we have exactly one consumed, - // destroy_value /after/ the end_borrow we will not optimize here. This means - // that this bug can only occur if the copy_value is only post-dominated by - // dead end blocks that use the value in a non-consuming way. - // - // TODO: There may be some way of sinking this into the loop below. - bool haveAnyLocalScopes = - llvm::any_of(borrowScopeIntroducers, [](BorrowedValue borrowScope) { - return borrowScope.isLocalScope(); - }); - - auto destroys = lr.getDestroyingUses(); - if (destroys.empty() && haveAnyLocalScopes) { - return false; - } - - // If we reached this point, then we know that all of our users can accept a - // guaranteed value and our owned value is destroyed only by a set of - // destroy_values. Check if: - // - // 1. All of our destroys are joint post-dominated by our end borrow scope - // set. If they do not, then the copy_value is lifetime extending the - // guaranteed value, we can not eliminate it. - // - // 2. If all of our destroy_values are dead end. In such a case, the linear - // lifetime checker will not perform any checks since it assumes that dead - // end destroys can be ignored. Since we are going to end the program - // anyways, we want to be conservative here and optimize only if we do not - // need to insert an end_borrow since all of our borrow introducers are - // non-local scopes. - { - bool foundNonDeadEnd = false; - for (auto *d : destroys) { - foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(d->getParentBlock()); - } - if (!foundNonDeadEnd && haveAnyLocalScopes) - return false; - SmallVector scratchSpace; - SmallPtrSet visitedBlocks; - if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { - return !borrowScope.areUsesWithinScope(lr.getAllConsumingUses(), - scratchSpace, visitedBlocks, - getDeadEndBlocks()); - })) { - return false; - } - } - - // Otherwise, we know that our copy_value/destroy_values are all completely - // within the guaranteed value scope. So we /could/ optimize it. Now check if - // we were truly dead or if we are dead if we can eliminate phi arg uses. If - // we need to handle the phi arg uses, we bail. After we reach a fixed point, - // we will try to eliminate this value then if we can find a complete set of - // all incoming values to our phi argument. - if (hasUnknownConsumingUseState == - OwnershipLiveRange::HasConsumingUse_t::YesButAllPhiArgs) { - auto opPhi = *OwnershipPhiOperand::get(lr.getSingleUnknownConsumingUse()); - SmallVector scratchSpace; - SmallPtrSet visitedBlocks; - - bool canOptimizePhi = opPhi.visitResults([&](SILValue value) { - SWIFT_DEFER { - scratchSpace.clear(); - visitedBlocks.clear(); - }; - - OwnershipLiveRange phiArgLR(value); - if (bool(phiArgLR.hasUnknownConsumingUse())) { - return false; - } - - if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) { - return !borrowScope.areUsesWithinScope( - phiArgLR.getAllConsumingUses(), scratchSpace, visitedBlocks, - getDeadEndBlocks()); - })) { - return false; - } - - return true; - }); - - if (canOptimizePhi) { - opPhi.visitResults([&](SILValue value) { - joinedOwnedIntroducerToConsumedOperands.insert(value, - opPhi.getOperand()); - return true; - }); - } - - return false; - } - - // Otherwise, our copy must truly not be needed, o RAUW and convert to - // guaranteed! - std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), getCallbacks()); - return true; -} - -/// If cvi only has destroy value users, then cvi is a dead live range. Lets -/// eliminate all such dead live ranges. -bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue( - CopyValueInst *cvi) { - // This is a cheap optimization generally. - - // See if we are lucky and have a simple case. - if (auto *op = cvi->getSingleUse()) { - if (auto *dvi = dyn_cast(op->getUser())) { - eraseInstruction(dvi); - eraseInstructionAndAddOperandsToWorklist(cvi); - return true; - } - } - - // If all of our copy_value users are destroy_value, zap all of the - // instructions. We begin by performing that check and gathering up our - // destroy_value. - SmallVector destroys; - if (!all_of(cvi->getUses(), [&](Operand *op) { - auto *dvi = dyn_cast(op->getUser()); - if (!dvi) - return false; - - // Stash dvi in destroys so we can easily eliminate it later. - destroys.push_back(dvi); - return true; - })) { - return false; - } - - // Now that we have a truly dead live range copy value, eliminate it! - while (!destroys.empty()) { - eraseInstruction(destroys.pop_back_val()); - } - eraseInstructionAndAddOperandsToWorklist(cvi); - return true; -} - -// Handle simple checking where we do not need to form live ranges and visit a -// bunch of instructions. -static bool canSafelyJoinSimpleRange(SILValue cviOperand, - DestroyValueInst *cviOperandDestroy, - CopyValueInst *cvi) { - // We only handle cases where our copy_value has a single consuming use that - // is not a forwarding use. We need to use the LiveRange functionality to - // guarantee correctness in the presence of forwarding uses. - // - // NOTE: This use may be any type of consuming use and may not be a - // destroy_value. - auto *cviConsumer = cvi->getSingleConsumingUse(); - if (!cviConsumer || isOwnedForwardingInstruction(cviConsumer->getUser())) { - return false; - } - - // Ok, we may be able to eliminate this. The main thing we need to be careful - // of here is that if the destroy_value is /after/ the consuming use of the - // operand of copy_value, we may have normal uses of the copy_value's operand - // that would become use-after-frees since we would be shrinking the lifetime - // of the object potentially. Consider the following SIL: - // - // %0 = ... - // %1 = copy_value %0 - // apply %cviConsumer(%1) - // apply %guaranteedUser(%0) - // destroy_value %0 - // - // Easily, if we were to eliminate the copy_value, destroy_value, the object's - // lifetime could potentially be shrunk before guaranteedUser is executed, - // causing guaranteedUser to be a use-after-free. - // - // As an extra wrinkle, until all interior pointer constructs (e.x.: - // project_box) are guaranteed to be guaranted by a begin_borrow, we can not - // in general safely shrink lifetimes. So even if we think we can prove that - // all non-consuming uses of %0 are before apply %cviConsumer, we may miss - // implicit uses that are not guarded yet by a begin_borrow, resulting in - // use-after-frees. - // - // With that in mind, we only handle cases today where we can prove that - // destroy_value is strictly before the consuming use of the operand. This - // guarantees that we are not shrinking the lifetime of the underlying object. - // - // First we handle the simple case: where the cviConsumer is a return inst. In - // such a case, we know for sure that cviConsumer post-dominates the - // destroy_value. - auto cviConsumerIter = cviConsumer->getUser()->getIterator(); - if (isa(cviConsumerIter)) { - return true; - } - - // Then see if our cviConsumer is in the same block as a return inst and the - // destroy_value is not. In that case, we know that the cviConsumer must - // post-dominate the destroy_value. - auto *cviConsumingBlock = cviConsumerIter->getParent(); - if (isa(cviConsumingBlock->getTerminator()) && - cviConsumingBlock != cviOperandDestroy->getParent()) { - return true; - } - - // Otherwise, we only support joining live ranges where the cvi and the cvi's - // operand's destroy are in the same block with the destroy_value of cvi - // operand needing to be strictly after the copy_value. This analysis can be - // made significantly stronger by using LiveRanges, but this is simple for - // now. - auto cviOperandDestroyIter = cviOperandDestroy->getIterator(); - if (cviConsumingBlock != cviOperandDestroyIter->getParent()) { - return false; - } - - // TODO: This should really be llvm::find, but for some reason, the templates - // do not match up given the current state of the iterators. This impl works - // in a pinch though. - return llvm::any_of( - llvm::make_range(cviOperandDestroyIter, - cviOperandDestroyIter->getParent()->end()), - [&](const SILInstruction &val) { return &*cviConsumerIter == &val; }); -} - -// # The Problem We Are Solving -// -// The main idea here is that we are trying to eliminate the simplest, easiest -// form of live range joining. Consider the following SIL: -// -// ``` -// %cviOperand = ... // @owned value -// %cvi = copy_value %cviOperand // copy of @owned value -// ... -// destroy_value %cviOperandDestroy // destruction of @owned value -// ... -// apply %consumingUser(%cvi) // destruction of copy of @owned value -// ``` -// -// We want to reduce reference count traffic by eliminating the middle -// copy/destroy yielding: -// -// ``` -// %cviOperand = ... // @owned value -// // *eliminated copy_value* -// ... -// // *eliminated destroy_value* -// ... -// apply %consumingUser(%cviOperand) // destruction of copy of @owned -// value -// ``` -// -// # Safety -// -// In order to do this safely, we need to take the union of the two objects -// lifetimes since we are only joining lifetimes. This ensures that we can rely -// on SILGen's correctness on inserting safe lifetimes. To keep this simple -// today we only optimize if the destroy_value and consuming user are in the -// same block and the consuming user is later in the block than the -// destroy_value. -// -// DISCUSSION: The reason why we do not shrink lifetimes today is that all -// interior pointers (e.x. project_box) are properly guarded by -// begin_borrow. Because of that we can not shrink lifetimes and instead rely on -// SILGen's correctness. -bool SemanticARCOptVisitor::tryJoiningCopyValueLiveRangeWithOperand( - CopyValueInst *cvi) { - // First do a quick check if our operand is owned. If it is not owned, we can - // not join live ranges. - SILValue operand = cvi->getOperand(); - if (operand.getOwnershipKind() != ValueOwnershipKind::Owned) { - return false; - } - - // Then check if our operand has a single destroy_value. If it does and that - // destroy_value is strictly before the consumer of our copy_value in the same - // block as the consumer of said copy_value then we can always join the live - // ranges. - // - // Example: - // - // ``` - // %1 = copy_value %0 - // ... - // destroy_value %0 - // apply %consumingUser(%1) - // ``` - // -> - // - // ``` - // apply %consumingUser(%0) - // ``` - // - // DISCUSSION: We need to ensure that the consuming use of the copy_value is - // strictly after the destroy_value to ensure that we do not shrink the live - // range of the operand if the operand has any normal uses beyond our copy - // value. Otherwise, we could have normal uses /after/ the consuming use of - // our copy_value. - if (auto *dvi = operand->getSingleConsumingUserOfType()) { - if (canSafelyJoinSimpleRange(operand, dvi, cvi)) { - eraseInstruction(dvi); - eraseAndRAUWSingleValueInstruction(cvi, operand); - return true; - } - } - - // Otherwise, we couldn't handle this case, so return false. - // - // NOTE: We would generally do a more complex analysis here to handle the more - // general case. That would most likely /not/ be a guaranteed optimization - // until we investigate/measure. - return false; -} - -bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) { - // If our copy value inst has only destroy_value users, it is a dead live - // range. Try to eliminate them. - if (eliminateDeadLiveRangeCopyValue(cvi)) { - return true; - } - - // Then see if copy_value operand's lifetime ends after our copy_value via a - // destroy_value. If so, we can join their lifetimes. - if (tryJoiningCopyValueLiveRangeWithOperand(cvi)) { - return true; - } - - // Then try to perform the guaranteed copy value optimization. - if (performGuaranteedCopyValueOptimization(cvi)) { - return true; - } - - return false; -} - //===----------------------------------------------------------------------===// // Top Level Entrypoint //===----------------------------------------------------------------------===// From c50e6d6bf3d1ceaad3d3e3dd8f06a15d90d3047e Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Sun, 30 Aug 2020 14:19:03 -0700 Subject: [PATCH 481/663] [swift-driver-compatibility] Update diagnostic for *-prefix-map args --- include/swift/AST/DiagnosticsFrontend.def | 8 ++++---- test/Driver/coverage-prefix-map.swift | 2 +- test/Driver/debug-prefix-map.swift | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 36471ecbc9d92..11ed4e6906297 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -328,11 +328,11 @@ ERROR(error_optimization_remark_pattern, none, "%0 in '%1'", (StringRef, StringRef)) ERROR(error_invalid_debug_prefix_map, none, - "invalid argument '%0' to -debug-prefix-map; it must be of the form " - "'original=remapped'", (StringRef)) + "values for '-debug-prefix-map' must be in the format 'original=remapped'" + ", but '%0' was provided", (StringRef)) ERROR(error_invalid_coverage_prefix_map, none, - "invalid argument '%0' to -coverage-prefix-map; it must be of the form " - "'original=remapped'", (StringRef)) + "values for '-coverage-prefix-map' must be in the format " + "'original=remapped', but '%0' was provided", (StringRef)) ERROR(error_unable_to_write_swift_ranges_file, none, diff --git a/test/Driver/coverage-prefix-map.swift b/test/Driver/coverage-prefix-map.swift index fd2ff8a5cbc2c..c4f42d0bff999 100644 --- a/test/Driver/coverage-prefix-map.swift +++ b/test/Driver/coverage-prefix-map.swift @@ -3,7 +3,7 @@ // RUN: %target-swiftc_driver -### -coverage-prefix-map old=n=ew %s 2>&1 | %FileCheck %s -check-prefix CHECK-COMPLEX // RUN: %target-swiftc_driver -### -coverage-prefix-map old= %s 2>&1 | %FileCheck %s -check-prefix CHECK-EMPTY -// CHECK-INVALID: error: invalid argument 'old' to -coverage-prefix-map +// CHECK-INVALID: error: values for '-coverage-prefix-map' must be in the format 'original=remapped', but 'old' was provided // CHECK-SIMPLE: coverage-prefix-map old=new // CHECK-COMPLEX: coverage-prefix-map old=n=ew // CHECK-EMPTY: coverage-prefix-map old= diff --git a/test/Driver/debug-prefix-map.swift b/test/Driver/debug-prefix-map.swift index 3483f3fe3c856..d23e72faf4fd5 100644 --- a/test/Driver/debug-prefix-map.swift +++ b/test/Driver/debug-prefix-map.swift @@ -3,7 +3,7 @@ // RUN: %target-swiftc_driver -### -debug-prefix-map old=n=ew %s 2>&1 | %FileCheck %s -check-prefix CHECK-COMPLEX // RUN: %target-swiftc_driver -### -debug-prefix-map old= %s 2>&1 | %FileCheck %s -check-prefix CHECK-EMPTY -// CHECK-INVALID: error: invalid argument 'old' to -debug-prefix-map +// CHECK-INVALID: error: values for '-debug-prefix-map' must be in the format 'original=remapped', but 'old' was provided // CHECK-SIMPLE: debug-prefix-map old=new // CHECK-COMPLEX: debug-prefix-map old=n=ew // CHECK-EMPTY: debug-prefix-map old= From df0a8b374601d9d0b7f3d66bc515ffbad4132ad0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 31 Aug 2020 22:06:35 -0400 Subject: [PATCH 482/663] DI: Track of initialization state of trivial fields in root class initializers While we don't need to destroy these fields, we still need to know when the class is _semantically_ fully initialized, since this will determine if we're going to release the class, running the deinitializer, or if we're going to deallocate the memory for the instance directly. --- .../Mandatory/DIMemoryUseCollector.h | 5 +++++ .../Mandatory/DefiniteInitialization.cpp | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h index 66a878cc5717f..1cea674c1e3b8 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h @@ -176,6 +176,11 @@ class DIMemoryObjectInfo { MemoryInst->isDerivedClassSelfOnly(); } + /// True if this memory object is the 'self' of a root class init method. + bool isRootClassSelf() const { + return isClassInitSelf() && MemoryInst->isRootSelf(); + } + /// True if this memory object is the 'self' of a non-root class init method. bool isNonRootClassSelf() const { return isClassInitSelf() && !MemoryInst->isRootSelf(); diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index da7370b39ec39..41ba220949ef2 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -1072,7 +1072,13 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) { // it for later. Once we've collected all of the conditional init/assigns, // we can insert a single control variable for the memory object for the // whole function. - if (!Use.onlyTouchesTrivialElements(TheMemory)) + // + // For root class initializers, we must keep track of initializations of + // trivial stored properties also, since we need to know when the object + // has been fully initialized when deciding if a strong_release should + // lower to a partial_dealloc_ref. + if (TheMemory.isRootClassSelf() || + !Use.onlyTouchesTrivialElements(TheMemory)) HasConditionalInitAssign = true; return; } @@ -2285,7 +2291,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() { // If this ambiguous store is only of trivial types, then we don't need to // do anything special. We don't even need keep the init bit for the // element precise. - if (Use.onlyTouchesTrivialElements(TheMemory)) + // + // For root class initializers, we must keep track of initializations of + // trivial stored properties also, since we need to know when the object + // has been fully initialized when deciding if a strong_release should + // lower to a partial_dealloc_ref. + if (!TheMemory.isRootClassSelf() && + Use.onlyTouchesTrivialElements(TheMemory)) continue; B.setInsertionPoint(Use.Inst); From 233eeea6cb025b04e112c723a27113a94f81c79e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 31 Aug 2020 18:27:53 -0400 Subject: [PATCH 483/663] DI: Correctly handle conditional destroy of 'self' in root class In a designated initializer of a non-root class, 'self' becomes fully initialized after the 'super.init' call, at which point escaping uses of 'self' become valid, and releases of 'self' are lowered to a 'strong_release' instruction, which runs the deinitializer. In a root class, 'self' becomes fully initialized after all stored properties have been initialized, at which point escaping uses of 'self' become valid. However, DI would still lower a conditional destroy of 'self' by destroying any initialized stored properties and freeing the object with 'dealloc_partial_ref'. This is incorrect, because 'self' may have escaped. In the non-conditional destroy case, we correctly lowered the release to a 'strong_release' if all stored properties are known to be initialized. Fix DI to handle the conditional destroy case by first checking if all bits in the control variable are set, and releasing the instance with 'strong_release' if so. The 'dealloc_partial_ref' is only emitted if not at least one stored property was not initialized. This ensures that we don't deallocate an instance that may have escaped. Fixes , , , . --- .../Mandatory/DefiniteInitialization.cpp | 76 ++++++- .../failable_initializers_root_class.swift | 176 ++++++++++++++ .../definite_init_root_class.swift | 214 ++++++++++++++++++ 3 files changed, 460 insertions(+), 6 deletions(-) create mode 100644 test/Interpreter/failable_initializers_root_class.swift create mode 100644 test/SILOptimizer/definite_init_root_class.swift diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index 41ba220949ef2..14a63285fb1f3 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -2230,6 +2230,32 @@ static SILValue testControlVariableBit(SILLocation Loc, {}, CondVal); } +/// Test if all bits in the control variable are set at the current +/// insertion point. +static SILValue testAllControlVariableBits(SILLocation Loc, + SILValue ControlVariableAddr, + Identifier &CmpEqFn, + SILBuilder &B) { + SILValue ControlVariable = + B.createLoad(Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial); + + SILValue CondVal = ControlVariable; + CanBuiltinIntegerType IVType = CondVal->getType().castTo(); + + if (IVType->getFixedWidth() == 1) + return CondVal; + + SILValue AllBitsSet = B.createIntegerLiteral(Loc, CondVal->getType(), -1); + if (!CmpEqFn.get()) + CmpEqFn = getBinaryFunction("cmp_eq", CondVal->getType(), + B.getASTContext()); + SILValue Args[] = { CondVal, AllBitsSet }; + + return B.createBuiltin(Loc, CmpEqFn, + SILType::getBuiltinIntegerType(1, B.getASTContext()), + {}, Args); +} + /// handleConditionalInitAssign - This memory object has some stores /// into (some element of) it that is either an init or an assign based on the /// control flow path through the function, or have a destroy event that happens @@ -2407,7 +2433,7 @@ SILValue LifetimeChecker::handleConditionalInitAssign() { void LifetimeChecker:: handleConditionalDestroys(SILValue ControlVariableAddr) { SILBuilderWithScope B(TheMemory.getUninitializedValue()); - Identifier ShiftRightFn, TruncateFn; + Identifier ShiftRightFn, TruncateFn, CmpEqFn; unsigned NumMemoryElements = TheMemory.getNumElements(); @@ -2534,12 +2560,50 @@ handleConditionalDestroys(SILValue ControlVariableAddr) { // Just conditionally destroy each memory element, and for classes, // also free the partially initialized object. if (!TheMemory.isNonRootClassSelf()) { - destroyMemoryElements(Loc, Availability); - processUninitializedRelease(Release, false, B.getInsertionPoint()); + assert(!Availability.isAllYes() && + "Should not end up here if fully initialized"); + + // For root class initializers, we check if all proeprties were + // dynamically initialized, and if so, treat this as a release of + // an initialized 'self', instead of tearing down the fields + // one by one and deallocating memory. + // + // This is required for correctness, since the condition that + // allows 'self' to escape is that all stored properties were + // initialized. So we cannot deallocate the memory if 'self' may + // have escaped. + // + // This also means the deinitializer will run if all stored + // properties were initialized. + if (TheMemory.isClassInitSelf() && + Availability.hasAny(DIKind::Partial)) { + auto CondVal = testAllControlVariableBits(Loc, ControlVariableAddr, + CmpEqFn, B); + + SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock; + + InsertCFGDiamond(CondVal, Loc, B, + ReleaseBlock, DeallocBlock, ContBlock); + + // If true, self was fully initialized and must be released. + B.setInsertionPoint(ReleaseBlock->begin()); + B.setCurrentDebugScope(ReleaseBlock->begin()->getDebugScope()); + Release->moveBefore(&*B.getInsertionPoint()); + + // If false, self is uninitialized and must be freed. + B.setInsertionPoint(DeallocBlock->begin()); + B.setCurrentDebugScope(DeallocBlock->begin()->getDebugScope()); + destroyMemoryElements(Loc, Availability); + processUninitializedRelease(Release, false, B.getInsertionPoint()); + } else { + destroyMemoryElements(Loc, Availability); + processUninitializedRelease(Release, false, B.getInsertionPoint()); + + // The original strong_release or destroy_addr instruction is + // always dead at this point. + deleteDeadRelease(CDElt.ReleaseID); + } - // The original strong_release or destroy_addr instruction is - // always dead at this point. - deleteDeadRelease(CDElt.ReleaseID); continue; } diff --git a/test/Interpreter/failable_initializers_root_class.swift b/test/Interpreter/failable_initializers_root_class.swift new file mode 100644 index 0000000000000..9caa08da0001e --- /dev/null +++ b/test/Interpreter/failable_initializers_root_class.swift @@ -0,0 +1,176 @@ +// RUN: %target-run-simple-swift + +// REQUIRES: executable_test + +import StdlibUnittest + + +var FailableInitTestSuite = TestSuite("FailableInit") + +var deinitCalled = 0 + +func mustFail(f: () -> T?) { + if f() != nil { + preconditionFailure("Didn't fail") + } +} + +func mustSucceed(f: () -> T?) { + if f() == nil { + preconditionFailure("Didn't succeed") + } +} + +class FirstClass { + var x: LifetimeTracked + + init?(n: Int) { + if n == 0 { + return nil + } + + x = LifetimeTracked(0) + + if n == 1 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("FirstClass") { + deinitCalled = 0 + + mustFail { FirstClass(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { FirstClass(n: 1) } + expectEqual(1, deinitCalled) + + mustSucceed { FirstClass(n: 2) } + expectEqual(2, deinitCalled) +} + +class FirstClassTrivial { + var x: Int + + init?(n: Int) { + if n == 0 { + return nil + } + + x = 0 + + if n == 1 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("FirstClassTrivial") { + deinitCalled = 0 + + mustFail { FirstClassTrivial(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { FirstClassTrivial(n: 1) } + expectEqual(1, deinitCalled) + + mustSucceed { FirstClassTrivial(n: 2) } + expectEqual(2, deinitCalled) +} + +class SecondClass { + var x: LifetimeTracked + var y: LifetimeTracked + + init?(n: Int) { + if n == 0 { + return nil + } + + x = LifetimeTracked(0) + + if n == 1 { + return nil + } + + y = LifetimeTracked(0) + + if n == 2 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("SecondClass") { + deinitCalled = 0 + + mustFail { SecondClass(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { SecondClass(n: 1) } + expectEqual(0, deinitCalled) + + mustFail { SecondClass(n: 2) } + expectEqual(1, deinitCalled) + + mustSucceed { SecondClass(n: 3) } + expectEqual(2, deinitCalled) +} + +class SecondClassTrivial { + var x: Int + var y: Int + + init?(n: Int) { + if n == 0 { + return nil + } + + x = 0 + + if n == 1 { + return nil + } + + y = 0 + + if n == 2 { + return nil + } + } + + deinit { + deinitCalled += 1 + } +} + +FailableInitTestSuite.test("SecondClassTrivial") { + deinitCalled = 0 + + mustFail { SecondClassTrivial(n: 0) } + expectEqual(0, deinitCalled) + + mustFail { SecondClassTrivial(n: 1) } + expectEqual(0, deinitCalled) + + mustFail { SecondClassTrivial(n: 2) } + expectEqual(1, deinitCalled) + + mustSucceed { SecondClassTrivial(n: 3) } + expectEqual(2, deinitCalled) +} + +runAllTests() diff --git a/test/SILOptimizer/definite_init_root_class.swift b/test/SILOptimizer/definite_init_root_class.swift new file mode 100644 index 0000000000000..89d304d3c2169 --- /dev/null +++ b/test/SILOptimizer/definite_init_root_class.swift @@ -0,0 +1,214 @@ +// RUN: %target-swift-frontend -emit-sil %s | %FileCheck %s + +class OtherClass {} + +class FirstClass { + var x: OtherClass + + // CHECK-LABEL: sil hidden @$s24definite_init_root_class10FirstClassC1nACSgs5Int32V_tcfc : $@convention(method) (Int32, @owned FirstClass) -> @owned Optional + init?(n: Int32) { + // CHECK: [[CONTROL:%.*]] = alloc_stack $Builtin.Int1 + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int1, 0 + // CHECK: store [[ZERO]] to [[CONTROL]] : $*Builtin.Int1 + + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int32, 0 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ZERO]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb1, bb2 + if n == 0 { + return nil + } + + // CHECK: bb1: + // CHECK: br bb5 + + // CHECK: bb2: + // CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type + // CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $FirstClass, #FirstClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [modify] [dynamic] %15 : $*OtherClass + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int1, -1 + // CHECK: store [[ONE]] to [[CONTROL]] : $*Builtin.Int1 + // CHECK: store [[OTHER]] to [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + x = OtherClass() + + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int32, 1 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ONE]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb3, bb4 + if n == 1 { + return nil + } + + // CHECK: bb3: + // CHECK: br bb5 + + // CHECK: bb4: + // CHECK: [[RESULT:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $FirstClass + // CHECK: br bb12([[RESULT]] : $Optional) + + // CHECK: bb5: + // CHECK: [[BIT:%.*]] = load [[CONTROL]] : $*Builtin.Int1 + // CHECK: cond_br [[BIT]], bb6, bb7 + + // CHECK: bb6: + // CHECK: strong_release %1 : $FirstClass + // CHECK: br bb11 + + // CHECK: bb7: + // CHECK: [[BIT:%.*]] = load [[CONTROL]] : $*Builtin.Int1 + // CHECK: cond_br [[BIT]], bb8, bb9 + + // CHECK: bb8: + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $FirstClass, #FirstClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [deinit] [static] [[X_ADDR]] : $*OtherClass + // CHECK: destroy_addr [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + // CHECK: br bb10 + + // CHECK: bb9: + // CHECK: br bb10 + + // CHECK: [[METATYPE:%.*]] = metatype $@thick FirstClass.Type + // CHECK: dealloc_partial_ref %1 : $FirstClass, [[METATYPE]] : $@thick FirstClass.Type + // CHECK: br bb11 + + // CHECK: bb11: + // CHECK: [[NIL:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK: br bb12([[NIL]] : $Optional) + + // CHECK: bb12([[RESULT:%.*]] : $Optional): + // CHECK: dealloc_stack [[CONTROL]] : $*Builtin.Int1 + // CHECK: return [[RESULT]] : $Optional + } +} + +class SecondClass { + var x: OtherClass + var y: OtherClass + + // CHECK-LABEL: sil hidden @$s24definite_init_root_class11SecondClassC1nACSgs5Int32V_tcfc : $@convention(method) (Int32, @owned SecondClass) -> @owned Optional { + init?(n: Int32) { + // CHECK: [[CONTROL:%.*]] = alloc_stack $Builtin.Int2 + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int2, 0 + // CHECK: store [[ZERO]] to [[CONTROL]] : $*Builtin.Int2 + + // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int32, 0 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ZERO]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb1, bb2 + if n == 0 { + return nil + } + + // CHECK: bb1: + // CHECK: br bb7 + + // CHECK: bb2: + // CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type + // CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [modify] [dynamic] [[X_ADDR]] : $*OtherClass + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int2, 1 + // CHECK: store [[ONE]] to [[CONTROL]] : $*Builtin.Int2 + // CHECK: store [[OTHER]] to [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + x = OtherClass() + + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int32, 1 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[ONE]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb3, bb4 + if n == 1 { + return nil + } + + // CHECK: bb3: + // CHECK: br bb7 + + // CHECK: bb4: + // CHECK: [[METATYPE:%.*]] = metatype $@thick OtherClass.Type + // CHECK: [[INIT:%.*]] = function_ref @$s24definite_init_root_class10OtherClassCACycfC : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[OTHER:%.*]] = apply [[INIT]]([[METATYPE]]) : $@convention(method) (@thick OtherClass.Type) -> @owned OtherClass + // CHECK: [[Y_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.y + // CHECK: [[Y_ACCESS:%.*]] = begin_access [modify] [dynamic] [[Y_ADDR]] : $*OtherClass + // CHECK: [[THREE:%.*]] = integer_literal $Builtin.Int2, -1 + // CHECK: store [[THREE]] to [[CONTROL]] : $*Builtin.Int2 + // CHECK: store [[OTHER]] to [[Y_ACCESS]] : $*OtherClass + // CHECK: end_access [[Y_ACCESS]] : $*OtherClass + y = OtherClass() + + // CHECK: [[TWO:%.*]] = integer_literal $Builtin.Int32, 2 + // CHECK: [[N:%.*]] = struct_extract %0 : $Int32, #Int32._value + // CHECK: [[CMP:%.*]] = builtin "cmp_eq_Int32"([[N]] : $Builtin.Int32, [[TWO]] : $Builtin.Int32) : $Builtin.Int1 + // CHECK: cond_br [[CMP]], bb5, bb6 + if n == 2 { + return nil + } + + // CHECK: bb5: + // CHECK: br bb7 + + // CHECK: bb6: + // CHECK: [[RESULT:%.*]] = enum $Optional, #Optional.some!enumelt, %1 : $SecondClass + // CHECK: br bb17([[RESULT]] : $Optional) + + // CHECK: bb7: + // CHECK: [[BITS:%.*]] = load [[CONTROL]] : $*Builtin.Int2 + // CHECK: [[THREE:%.*]] = integer_literal $Builtin.Int2, -1 + // CHECK: [[BIT:%.*]] = builtin "cmp_eq_Int2"([[BITS]] : $Builtin.Int2, [[THREE]] : $Builtin.Int2) : $Builtin.Int1 + // CHECK: cond_br [[BIT]], bb8, bb9 + + // CHECK: bb8: + // CHECK: strong_release %1 : $SecondClass + // CHECK: br bb16 + + // CHECK: bb9: + // CHECK: [[BITS:%.*]] = load [[CONTROL]] : $*Builtin.Int2 + // CHECK: [[BIT:%.*]] = builtin "trunc_Int2_Int1"([[BITS]] : $Builtin.Int2) : $Builtin.Int1 + // CHECK: cond_br [[BIT]], bb10, bb11 + + // CHECK: bb10: + // CHECK: [[X_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.x + // CHECK: [[X_ACCESS:%.*]] = begin_access [deinit] [static] [[X_ADDR]] : $*OtherClass + // CHECK: destroy_addr [[X_ACCESS]] : $*OtherClass + // CHECK: end_access [[X_ACCESS]] : $*OtherClass + // CHECK: br bb12 + + // CHECK: bb11: + // CHECK: br bb12 + + // CHECK: bb12: + // CHECK: [[BITS:%.*]] = load [[CONTROL]] : $*Builtin.Int2 + // CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int2, 1 + // CHECK: [[TMP:%.*]] = builtin "lshr_Int2"([[BITS]] : $Builtin.Int2, [[ONE]] : $Builtin.Int2) : $Builtin.Int2 + // CHECK: [[BIT:%.*]] = builtin "trunc_Int2_Int1"([[TMP]] : $Builtin.Int2) : $Builtin.Int1 + // CHECK: cond_br [[BIT]], bb13, bb14 + + // CHECK: bb13: + // CHECK: [[Y_ADDR:%.*]] = ref_element_addr %1 : $SecondClass, #SecondClass.y + // CHECK: [[Y_ACCESS:%.*]] = begin_access [deinit] [static] [[Y_ADDR]] : $*OtherClass + // CHECK: destroy_addr [[Y_ACCESS]] : $*OtherClass + // CHECK: end_access [[Y_ACCESS]] : $*OtherClass + // CHECK: br bb15 + + // CHECK: bb14: + // CHECK: br bb15 + + // CHECK: bb15: + // CHECK: [[METATYPE:%.*]] = metatype $@thick SecondClass.Type + // CHECK: dealloc_partial_ref %1 : $SecondClass, [[METATYPE]] : $@thick SecondClass.Type + // CHECK: br bb16 + + // CHECK: bb16: + // CHECK: [[NIL:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK: br bb17([[NIL]] : $Optional) + + // CHECK: bb17([[RESULT:%.*]] : $Optional): + // CHECK: dealloc_stack [[CONTROL]] : $*Builtin.Int2 + // CHECK: return [[RESULT]] : $Optional + } +} From fb09435293e755c81cc5e0984281b342bf845d58 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Mon, 31 Aug 2020 22:16:31 -0400 Subject: [PATCH 484/663] [Docs] Rework educational note on protocol type non-conformance --- .../protocol-type-non-conformance.md | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md index 47cc95193a130..fdfc2da95c797 100644 --- a/userdocs/diagnostics/protocol-type-non-conformance.md +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -1,46 +1,59 @@ -# Protocol type not conforming to itself -Protocols in Swift may be used as types. Protocols as types are sometimes called existential types. +# Protocol Types Cannot Conform to Protocols +In Swift, a protocol that does not have `Self` or associated type requirements can be used as a type. You can use a variable or constant of a protocol type, also called an __existential type__, to hold a value of any conforming type: ```swift -protocol P {} - -struct S: P {} +protocol Animal { + func makeNoise() + static var species: String { get } +} +struct Dog: Animal { + func makeNoise() { print("Woof") } + static var species: String = "Canus familiaris" +} +struct Cat: Animal { + func makeNoise() { print("Meow") } + static var species: String = "Felis catus" +} -var s: P = S() // This creates existential type because the protocol P is used as a type +var animal: Animal // `Animal` is used here as a type. +animal = Dog() +animal.makeNoise() // Prints "Woof". +animal = Cat() +animal.makeNoise() // Prints "Meow". ``` -However, a protocol type does not conform to protocols - not even the protocol itself. -Allowing existential types to conform to protocols is unsound. For protocols with static method, initializer, or associated type requirements, the implementation of these requirements cannot be accessed from the protocol type - accessing these kinds of requirements must be done using a concrete type. - -Let's walk through the example below: +Notice that it is possible to invoke the method `makeNoise()` on a value of type `Animal`, just as it is possible to do so on a value of concrete type `Dog` or `Cat`. However, the static property `species` is not available for the existential type: ```swift -protocol Word: Hashable { - var word: String { get } -} +print(Dog.species) // Prints "Canus familiaris" +print(Cat.species) // Prints "Felis catus" +print(Animal.species) // Error +``` -struct Singular: Word { - var word: String -} +Since a type conforms to a protocol only when it satisfies _all_ of that protocol's requirements, the existential type `Animal` does not conform to the protocol `Animal` because it cannot satisfy its own requirement for the static property `species`: -struct Plural: Word { - var word: String +```swift +func declareAnimalSpecies(_ animal: T) { + animal.makeNoise() + print("My species is known as \(T.species)") } -let singularWord = Singular(word: "mango") -let pluralWord = Plural(word: "mangoes") - -let wordPairDict: [Word: Word] = [singularWord: pluralWord] // Error +let dog = Dog() +declareAnimalSpecies(dog) +// Prints: +// "Woof" +// "My species is known as Canus familiaris" +declareAnimalSpecies(animal) +// Error: protocol type 'Animal' cannot conform to 'Animal'... ``` -One workaround to fix this problem is to use type erasure for the protocol `Word`. Think of type erasure as a way to hide an object's type. Since `Word` is of type `Hashable`, we already have `AnyHashable` type erasure available in the standard library which we can easily use here. +In general, any initializers, static members, and associated types required by a protocol can be used only via conforming concrete types. Although Swift allows a protocol that requires initializers or static members to be used as a type, that type _does not and cannot_ conform to the protocol itself. -```swift -// The fix -let wordPairDict: [AnyHashable: AnyHashable] = [singularWord: pluralWord] -``` +Currently, even if a protocol `P` requires no initializers or static members, the existential type `P` does not conform to `P` (with exceptions below). This restriction allows library authors to add such requirements (initializers or static members) to an existing protocol without breaking their users' source code. + +Concrete types that _do_ conform to protocols can provide functionality similar to that of existential types. For example, the standard library provides the `AnyHashable` type for `Hashable` values. Manual implementation of such __type erasure__ can require specific knowledge of the semantic requirements for each protocol involved and is beyond the scope of this discussion. -# Exceptions -`@objc` protocol type with no static requirements however do conform to its own protocol. Another exception is the `Error` Swift protocol. +## Exceptions +The Swift protocol `Error` has no requirements and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. From 33e0b9663958a1f0542e0d8f5326e87a31cb4063 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Mon, 31 Aug 2020 23:42:24 -0400 Subject: [PATCH 485/663] [Docs] Revise wording for nominal types educational note --- userdocs/diagnostics/nominal-types.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/userdocs/diagnostics/nominal-types.md b/userdocs/diagnostics/nominal-types.md index a4a085308c9cd..55766430b10a3 100644 --- a/userdocs/diagnostics/nominal-types.md +++ b/userdocs/diagnostics/nominal-types.md @@ -1,6 +1,7 @@ -# Nominal types -In Swift, a type is considered a nominal type if it is named. In other words, it has been defined by declaring the type somewhere in code. Examples of nominal types include classes, structs and enums, all of which must be declared before using them. Nominal types are an important concept in Swift because they can be extended, explicitly initialized using the `MyType()` syntax, and may conform to protocols. +# Nominal Types -In contrast, non-nominal types have none of these capabilities. A non-nominal type is any type which is not nominal. They are sometimes called "structural types" because they are usually obtained by composing other types. Examples include function types like `(Int) -> (String)`, tuple types like `(Int, String)`, metatypes like `Int.Type`, and special types like `Any` and `AnyObject`. +In Swift, a type is considered a nominal type if it has been explicitly named by a declaration somewhere in code. Examples of nominal types include classes, structures and enumerations. Nominal types are an important concept in Swift because they may conform to protocols, be extended, and have values created using the initializer syntax `MyType()`. -Whether the name of a protocol refers to a nominal or non-nominal type depends on where it appears in code. When used in a declaration or extension like `extension MyProtocol { … }`, `MyProtocol` refers to a protocol type, which is nominal. This means that it may be extended and conform to protocols. However, when written as the type of a constant or variable, `MyProtocol` instead refers to a non-nominal, existential type. As a result, code like `let value: MyProtocol = MyProtocol()` is not allowed because `MyProtocol` refers to a non-nominal type in this context and cannot be explicitly initialized. +In contrast, non-nominal types do not have these capabilities. Many are obtained by composing other types. Examples include function types like `(Int) -> (String)`, tuple types like `(Int, String)`, metatypes like `Int.Type`, and special types like `Any` and `AnyObject`. + +Since a protocol is named by a declaration in code, it may conform to (in other words, refine) other protocols and it may be extended. However, when written as the type of a constant or variable such as `let value: MyProtocol`, the name refers to a distinct, non-nominal existential type that provides a "box" for a value of any concrete type that conforms to the protocol. The existential type itself does not conform to any protocols and cannot be extended, and a value cannot be created using the initializer syntax `MyProtocol()`. \ No newline at end of file From 335ae5ffc20abf3392ad6cf57b9dafc544b482d2 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Mon, 31 Aug 2020 23:57:34 -0400 Subject: [PATCH 486/663] Incorporate reviewer feedback --- userdocs/diagnostics/protocol-type-non-conformance.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md index fdfc2da95c797..28136d98565fc 100644 --- a/userdocs/diagnostics/protocol-type-non-conformance.md +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -31,7 +31,7 @@ print(Cat.species) // Prints "Felis catus" print(Animal.species) // Error ``` -Since a type conforms to a protocol only when it satisfies _all_ of that protocol's requirements, the existential type `Animal` does not conform to the protocol `Animal` because it cannot satisfy its own requirement for the static property `species`: +Since a type conforms to a protocol only when it satisfies _all_ of that protocol's requirements, the existential type `Animal` does not conform to the protocol `Animal` because it cannot satisfy the protocol's requirement for the static property `species`: ```swift func declareAnimalSpecies(_ animal: T) { @@ -54,6 +54,8 @@ Currently, even if a protocol `P` requires no initializers or static members, th Concrete types that _do_ conform to protocols can provide functionality similar to that of existential types. For example, the standard library provides the `AnyHashable` type for `Hashable` values. Manual implementation of such __type erasure__ can require specific knowledge of the semantic requirements for each protocol involved and is beyond the scope of this discussion. +For more on using existential types, see [Protocols as Types](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID275) in _The Swift Programming Language_. + ## Exceptions -The Swift protocol `Error` has no requirements and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. +The Swift protocol `Error` has no requirements and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. \ No newline at end of file From e34a065c7e9967f821c9f24795f03556ca1ab4cf Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Tue, 1 Sep 2020 00:00:53 -0400 Subject: [PATCH 487/663] Align error capitalization and make a minor rewording --- userdocs/diagnostics/protocol-type-non-conformance.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md index 28136d98565fc..1654367811033 100644 --- a/userdocs/diagnostics/protocol-type-non-conformance.md +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -28,7 +28,7 @@ Notice that it is possible to invoke the method `makeNoise()` on a value of type ```swift print(Dog.species) // Prints "Canus familiaris" print(Cat.species) // Prints "Felis catus" -print(Animal.species) // Error +print(Animal.species) // error: static member 'species' cannot be used... ``` Since a type conforms to a protocol only when it satisfies _all_ of that protocol's requirements, the existential type `Animal` does not conform to the protocol `Animal` because it cannot satisfy the protocol's requirement for the static property `species`: @@ -45,7 +45,7 @@ declareAnimalSpecies(dog) // "Woof" // "My species is known as Canus familiaris" declareAnimalSpecies(animal) -// Error: protocol type 'Animal' cannot conform to 'Animal'... +// error: protocol type 'Animal' cannot conform to 'Animal'... ``` In general, any initializers, static members, and associated types required by a protocol can be used only via conforming concrete types. Although Swift allows a protocol that requires initializers or static members to be used as a type, that type _does not and cannot_ conform to the protocol itself. @@ -58,4 +58,4 @@ For more on using existential types, see [Protocols as Types](https://docs.swift ## Exceptions -The Swift protocol `Error` has no requirements and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. \ No newline at end of file +The Swift protocol `Error` has no required members and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. \ No newline at end of file From 8229f71a5003b053c6e2c989bdd905f919cb94f8 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Tue, 1 Sep 2020 00:08:37 -0400 Subject: [PATCH 488/663] Add a reference to TSPL --- userdocs/diagnostics/nominal-types.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/userdocs/diagnostics/nominal-types.md b/userdocs/diagnostics/nominal-types.md index 55766430b10a3..bd3c55312ece5 100644 --- a/userdocs/diagnostics/nominal-types.md +++ b/userdocs/diagnostics/nominal-types.md @@ -4,4 +4,6 @@ In Swift, a type is considered a nominal type if it has been explicitly named by In contrast, non-nominal types do not have these capabilities. Many are obtained by composing other types. Examples include function types like `(Int) -> (String)`, tuple types like `(Int, String)`, metatypes like `Int.Type`, and special types like `Any` and `AnyObject`. -Since a protocol is named by a declaration in code, it may conform to (in other words, refine) other protocols and it may be extended. However, when written as the type of a constant or variable such as `let value: MyProtocol`, the name refers to a distinct, non-nominal existential type that provides a "box" for a value of any concrete type that conforms to the protocol. The existential type itself does not conform to any protocols and cannot be extended, and a value cannot be created using the initializer syntax `MyProtocol()`. \ No newline at end of file +Since a protocol is named by a declaration in code, it may conform to (in other words, refine) other protocols and it may be extended. However, when written as the type of a constant or variable such as `let value: MyProtocol`, the name refers to a distinct, non-nominal existential type that provides a "box" for a value of any concrete type that conforms to the protocol. The existential type itself does not conform to any protocols and cannot be extended, and a value cannot be created using the initializer syntax `MyProtocol()`. + +For more on using existential types, see [Protocols as Types](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID275) in _The Swift Programming Language_. \ No newline at end of file From 6a99fde6a6e5d85741c509eeed9557611006c830 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Sep 2020 00:06:42 -0700 Subject: [PATCH 489/663] [CSBindings] Delay binding chain result if type is an optional of a type variable If subtyping is allowed for a result type of an implicit member chain, let's delay binding it to an optional until its object type resolved too or it has been determined that there is no possibility to resolve it. Otherwise we might end up missing solutions since it's allowed to implicitly unwrap base type but it can't be done early - type variable representing chain's result type has a different l-valueness comparing to generic parameter of an optional. This used to work before due to a hack in constraint generator where unresolved member with arguments would return base type (which doesn't allow l-value) instead of a result type. Resolves: rdar://problem/68094328 --- lib/Sema/CSBindings.cpp | 18 ++++++++++++++ test/expr/delayed-ident/member_chains.swift | 27 +++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index a82b389991788..d9f4d7e8fc3e3 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -743,6 +743,24 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( return None; } + // If subtyping is allowed and this is a result of an implicit member chain, + // let's delay binding it to an optional until its object type resolved too or + // it has been determined that there is no possibility to resolve it. Otherwise + // we might end up missing solutions since it's allowed to implicitly unwrap + // base type of the chain but it can't be done early - type variable + // representing chain's result type has a different l-valueness comparing + // to generic parameter of the optional. + if (kind == AllowedBindingKind::Subtypes) { + auto *locator = typeVar->getImpl().getLocator(); + if (locator && + locator->isLastElement()) { + auto objectType = type->getOptionalObjectType(); + if (objectType && objectType->isTypeVariableOrMember()) { + result.PotentiallyIncomplete = true; + } + } + } + if (type->is() && !typeVar->getImpl().canBindToInOut()) type = LValueType::get(type->getInOutObjectType()); if (type->is() && !typeVar->getImpl().canBindToLValue()) diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index 2691574dbd321..a2684adf0d310 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -344,3 +344,30 @@ extension CurriedGeneric where T == Int { let _: CurriedGeneric = .createInt(CurriedGeneric())() let _: CurriedGeneric = .create(CurriedGeneric())(Int.self) + +// rdar://problem/68094328 - failed to compile unresolved member with implicit optional promotion +func rdar68094328() { + struct S { + init(string: String) {} + + var value: S { + get { S(string: "") } + } + + func baz(str: String) -> S { + S(string: str) + } + } + + class C { + func bar(_: S) {} + } + + func foo(_: (C) -> (T) -> Void, _: T?) {} + + func test(str: String) { + foo(C.bar, .init(string: str)) // Ok + foo(C.bar, .init(string: str).value) // Ok + foo(C.bar, .init(string: str).baz(str: "")) // Ok + } +} From 2e27704635830edc709f60fdb44621e0280a18c9 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 1 Sep 2020 11:05:43 +0100 Subject: [PATCH 490/663] Remove unused `swift_once_real` workaround --- include/swift/Runtime/Once.h | 4 ---- .../public/runtime/CompatibilityOverride.cpp | 5 ----- stdlib/public/runtime/CompatibilityOverride.h | 18 ++---------------- stdlib/public/runtime/HeapObject.cpp | 6 ------ 4 files changed, 2 insertions(+), 31 deletions(-) diff --git a/include/swift/Runtime/Once.h b/include/swift/Runtime/Once.h index 190d74654b256..f9931edf5b9bf 100644 --- a/include/swift/Runtime/Once.h +++ b/include/swift/Runtime/Once.h @@ -48,10 +48,6 @@ typedef std::once_flag swift_once_t; /// extent of type swift_once_t. SWIFT_RUNTIME_EXPORT void swift_once(swift_once_t *predicate, void (*fn)(void *), void *context); -#ifdef __wasm__ -// WebAssembly: hack -void swift_once_real(swift_once_t *predicate, void (*fn)(void *), void *context); -#endif } diff --git a/stdlib/public/runtime/CompatibilityOverride.cpp b/stdlib/public/runtime/CompatibilityOverride.cpp index 8ebc72ee5e702..000ff0dff2600 100644 --- a/stdlib/public/runtime/CompatibilityOverride.cpp +++ b/stdlib/public/runtime/CompatibilityOverride.cpp @@ -51,12 +51,7 @@ static_assert(std::is_pod::value, static OverrideSection *getOverrideSectionPtr() { static OverrideSection *OverrideSectionPtr; static swift_once_t Predicate; - // WebAssembly: hack -#ifdef __wasm__ - swift_once_real(&Predicate, [](void *) { -#else swift_once(&Predicate, [](void *) { -#endif size_t Size; OverrideSectionPtr = static_cast( lookupSection("__DATA", "__swift53_hooks", &Size)); diff --git a/stdlib/public/runtime/CompatibilityOverride.h b/stdlib/public/runtime/CompatibilityOverride.h index 25a3b1e3fc0ec..b3b39b2f67c7a 100644 --- a/stdlib/public/runtime/CompatibilityOverride.h +++ b/stdlib/public/runtime/CompatibilityOverride.h @@ -48,7 +48,7 @@ namespace swift { Override_ ## name getOverride_ ## name(); #include "CompatibilityOverride.def" -#ifndef __wasm__ + /// Used to define an override point. The override point #defines the appropriate /// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes /// the file to generate the override points. The original implementation of the @@ -64,23 +64,9 @@ namespace swift { return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ return swift_ ## name ## Impl namedArgs; \ } -#else -// WebAssembly: hack: change to swift_once_real -#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ - attrs ccAttrs ret namespace swift_ ## name typedArgs { \ - static Override_ ## name Override; \ - static swift_once_t Predicate; \ - swift_once_real(&Predicate, [](void *) { \ - Override = getOverride_ ## name(); \ - }, nullptr); \ - if (Override != nullptr) \ - return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ - return swift_ ## name ## Impl namedArgs; \ - } -#endif #endif // #else SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES } /* end namespace swift */ -#endif /* COMPATIBILITY_OVERRIDE_H */ +#endif /* COMPATIBILITY_OVERRIDE_H */ \ No newline at end of file diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 246ac6aa0b14b..b7f739061a8b9 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -171,13 +171,7 @@ swift::swift_initStaticObject(HeapMetadata const *metadata, // refcount to 1 while another thread already incremented it - and would // decrement it to 0 afterwards. InitStaticObjectContext Ctx = { object, metadata }; -#ifdef __wasm__ - // WebAssembly: hack: swift_once has been modified to take a function pointer without a parameter. - // so use the _real version that does have a parameter - swift_once_real(token, initStaticObjectWithContext, &Ctx); -#else swift_once(token, initStaticObjectWithContext, &Ctx); -#endif return object; } From b12a7053cbf4370a7291c8f241a7d53475baeab5 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Tue, 1 Sep 2020 14:07:00 +0200 Subject: [PATCH 491/663] SILOptimizer: add some dump() functions to the Existential utility classes. For better debugging. --- .../swift/SILOptimizer/Utils/Existential.h | 6 +++ lib/SILOptimizer/Utils/Existential.cpp | 37 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/swift/SILOptimizer/Utils/Existential.h b/include/swift/SILOptimizer/Utils/Existential.h index 75c88cf388f0a..5436654f71a2c 100644 --- a/include/swift/SILOptimizer/Utils/Existential.h +++ b/include/swift/SILOptimizer/Utils/Existential.h @@ -49,6 +49,8 @@ struct OpenedArchetypeInfo { assert(!OpenedArchetype || (OpenedArchetypeValue && ExistentialValue)); return OpenedArchetype; } + + void dump() const; }; /// Record conformance and concrete type info derived from an init_existential @@ -102,6 +104,8 @@ struct ConcreteExistentialInfo { CanType selfTy = P->getSelfInterfaceType()->getCanonicalType(); return ExistentialSubs.lookupConformance(selfTy, P); } + + void dump() const; private: void initializeSubstitutionMap( @@ -131,6 +135,8 @@ struct ConcreteOpenedExistentialInfo { assert(CEI->isValid()); return true; } + + void dump() const; }; } // end namespace swift diff --git a/lib/SILOptimizer/Utils/Existential.cpp b/lib/SILOptimizer/Utils/Existential.cpp index 9092171488767..3aa840b7a3a03 100644 --- a/lib/SILOptimizer/Utils/Existential.cpp +++ b/lib/SILOptimizer/Utils/Existential.cpp @@ -433,3 +433,40 @@ ConcreteOpenedExistentialInfo::ConcreteOpenedExistentialInfo( } CEI->isConcreteValueCopied |= OAI.isOpenedValueCopied; } + +void LLVM_ATTRIBUTE_USED OpenedArchetypeInfo::dump() const { + if (!isValid()) { + llvm::dbgs() << "invalid OpenedArchetypeInfo\n"; + return; + } + llvm::dbgs() << "OpendArchetype: "; + OpenedArchetype->dump(llvm::dbgs()); + llvm::dbgs() << "OpendArchetypeValue: "; + OpenedArchetypeValue->dump(); + llvm::dbgs() << (isOpenedValueCopied ? "copied " : "") << "ExistentialValue: "; + ExistentialValue->dump(); +} + +void LLVM_ATTRIBUTE_USED ConcreteExistentialInfo::dump() const { + llvm::dbgs() << "ExistentialType: "; + ExistentialType->dump(llvm::dbgs()); + llvm::dbgs() << "ConcreteType: "; + ConcreteType->dump(llvm::dbgs()); + llvm::dbgs() << (isConcreteValueCopied ? "copied " : "") << "ConcreteValue: "; + ConcreteValue->dump(); + if (ConcreteTypeDef) { + llvm::dbgs() << "ConcreteTypeDef: "; + ConcreteTypeDef->dump(); + } + ExistentialSubs.dump(llvm::dbgs()); + llvm::dbgs() << '\n'; +} + +void LLVM_ATTRIBUTE_USED ConcreteOpenedExistentialInfo::dump() const { + OAI.dump(); + if (CEI) { + CEI->dump(); + } else { + llvm::dbgs() << "no ConcreteExistentialInfo\n"; + } +} From b9612b2edb65aab2d32c7eac42ca70d9ded896f3 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Tue, 1 Sep 2020 14:23:06 +0200 Subject: [PATCH 492/663] SILCombine: fix an assertion crash in SILCombine when casting AnyClass to Any This caused a problem when propagating the concrete type of an existential: if the concrete type is itself an opened existential, it was not added to the OpenedArchetypeTracker. https://bugs.swift.org/browse/SR-13444 rdar://problem/68077098 --- .../SILCombiner/SILCombinerApplyVisitors.cpp | 2 ++ .../SILCombiner/SILCombinerMiscVisitors.cpp | 3 ++- test/SILOptimizer/sil_combine.sil | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index fd5d3a012b555..4774b9fd46a75 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -806,6 +806,8 @@ void SILCombiner::buildConcreteOpenedExistentialInfos( // BuilderContext before rewriting any uses of the ConcreteType. OpenedArchetypesTracker.addOpenedArchetypeDef( cast(CEI.ConcreteType), CEI.ConcreteTypeDef); + } else if (auto *I = CEI.ConcreteValue->getDefiningInstruction()) { + OpenedArchetypesTracker.registerUsedOpenedArchetypes(I); } } } diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp index c499356dfbea5..4321485140fb2 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp @@ -554,7 +554,8 @@ SILInstruction *SILCombiner::visitAllocStackInst(AllocStackInst *AS) { // Be careful with open archetypes, because they cannot be moved before // their definitions. if (IEI && !OEI && - !IEI->getLoweredConcreteType().isOpenedExistential()) { + !IEI->getLoweredConcreteType().hasOpenedExistential()) { + assert(!IEI->getLoweredConcreteType().isOpenedExistential()); auto *ConcAlloc = Builder.createAllocStack( AS->getLoc(), IEI->getLoweredConcreteType(), AS->getVarInfo()); IEI->replaceAllUsesWith(ConcAlloc); diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil index 145399c069f35..c3c8c95051839 100644 --- a/test/SILOptimizer/sil_combine.sil +++ b/test/SILOptimizer/sil_combine.sil @@ -3508,6 +3508,33 @@ bb0(%0 : $VV): return %26 : $() } +sil @any_to_object : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject + +// CHECK-LABEL: sil @dont_crash_when_propagating_existentials +// CHECK: [[EM:%[0-9]+]] = init_existential_metatype %0 +// CHECK: [[S:%[0-9]+]] = alloc_stack $Any +// CHECK: [[M:%[0-9]+]] = open_existential_metatype [[EM]] +// CHECK: [[E:%[0-9]+]] = init_existential_addr [[S]] +// CHECK: store [[M]] to [[E]] +// CHECK: apply {{%[0-9]+}}<(@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type>([[E]]) +// CHECK: } // end sil function 'dont_crash_when_propagating_existentials' +sil @dont_crash_when_propagating_existentials : $@convention(thin) () -> @owned AnyObject { +bb0: + %0 = metatype $@thick C.Type + %1 = init_existential_metatype %0 : $@thick C.Type, $@thick AnyObject.Type + %3 = alloc_stack $Any, let, name "object" + %4 = open_existential_metatype %1 : $@thick AnyObject.Type to $@thick (@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type + %5 = init_existential_addr %3 : $*Any, $(@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type + store %4 to %5 : $*@thick (@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134") AnyObject).Type + %7 = open_existential_addr immutable_access %3 : $*Any to $*@opened("5F9F1B04-EC40-11EA-9534-8C8590A6A134") Any + %8 = function_ref @any_to_object : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject + %9 = apply %8<@opened("5F9F1B04-EC40-11EA-9534-8C8590A6A134") Any>(%7) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject + destroy_addr %3 : $*Any + dealloc_stack %3 : $*Any + return %9 : $AnyObject +} + + // CHECK-LABEL: sil @remove_unused_alloc_ref // CHECK-NEXT: bb0 // CHECK-NEXT: %0 = tuple () From 8687c5442783118fd3c4b805b8a0ff6db25e80f8 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 1 Sep 2020 15:38:52 +0100 Subject: [PATCH 493/663] Cleanup `ThreadLocalStorage.cpp` ifdefs --- stdlib/public/stubs/ThreadLocalStorage.cpp | 36 +--------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index c520b08bc2df4..0f0c23e6c1d79 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -54,41 +54,7 @@ _stdlib_thread_key_create(__swift_thread_key_t * _Nonnull key, #endif -#if defined(__wasi__) -#include -using __swift_thread_key_destructor = void (*)(void *); - -struct _stdlib_tls_element_t { - const void *value; - __swift_thread_key_destructor destructor; -}; - -using _stdlib_tls_map_t = std::map<__swift_thread_key_t, _stdlib_tls_element_t>; -static void *_stdlib_tls_map; - -static inline int _stdlib_thread_key_create(__swift_thread_key_t *key, - __swift_thread_key_destructor destructor) { - if (!_stdlib_tls_map) - _stdlib_tls_map = new _stdlib_tls_map_t(); - auto *map = (_stdlib_tls_map_t *)_stdlib_tls_map; - *key = map->size(); - _stdlib_tls_element_t element = { nullptr, destructor }; - map->insert(std::make_pair(*key, element)); - return 0; -} - -static inline void *_stdlib_thread_getspecific(__swift_thread_key_t key) { - auto *map = (_stdlib_tls_map_t *)_stdlib_tls_map; - return const_cast(map->operator[](key).value); -} - -static inline int _stdlib_thread_setspecific(__swift_thread_key_t key, const void *value) { - auto *map = (_stdlib_tls_map_t *)_stdlib_tls_map; - map->operator[](key).value = value; - return 0; -} - -#elif defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) +#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) SWIFT_RUNTIME_STDLIB_INTERNAL void * From ecc5b90aa5fb832188ab9d8d50da6f9ef6ec2eb0 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Mon, 31 Aug 2020 21:52:20 -0300 Subject: [PATCH 494/663] [CodeCompletion] Do not erase dot for code completion key path optiona root unwrapped members --- lib/IDE/CodeCompletion.cpp | 8 ++- ...omplete_swift_key_path_optional_root.swift | 55 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 test/IDE/complete_swift_key_path_optional_root.swift diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 4d14814a55103..8488e6079ea3b 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -3725,8 +3725,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { llvm::SaveAndRestore ChangeNeedOptionalUnwrap(NeedOptionalUnwrap, true); if (DotLoc.isValid()) { + // Let's not erase the dot if the completion is after a swift key path + // root because \A?.?.member is the correct way to access wrapped type + // member from an optional key path root. + auto loc = IsAfterSwiftKeyPathRoot ? DotLoc.getAdvancedLoc(1) : DotLoc; NumBytesToEraseForOptionalUnwrap = Ctx.SourceMgr.getByteDistance( - DotLoc, Ctx.SourceMgr.getCodeCompletionLoc()); + loc, Ctx.SourceMgr.getCodeCompletionLoc()); } else { NumBytesToEraseForOptionalUnwrap = 0; } @@ -5930,7 +5934,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { if (!OnRoot && KPE->getComponents().back().getKind() == KeyPathExpr::Component::Kind::OptionalWrap) { // KeyPath expr with '?' (e.g. '\Ty.[0].prop?.another'). - // Althogh expected type is optional, we should unwrap it because it's + // Although expected type is optional, we should unwrap it because it's // unwrapped. baseType = baseType->getOptionalObjectType(); } diff --git a/test/IDE/complete_swift_key_path_optional_root.swift b/test/IDE/complete_swift_key_path_optional_root.swift new file mode 100644 index 0000000000000..c80822c601c4f --- /dev/null +++ b/test/IDE/complete_swift_key_path_optional_root.swift @@ -0,0 +1,55 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_INFER_DOT_OPTIONAL | %FileCheck %s -check-prefix=PERSONTYPE-INFER-DOT-OPT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_DOT_OPTIONAL | %FileCheck %s -check-prefix=PERSONTYPE-DOT-OPT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_DOT_OPTIONAL_SPACE | %FileCheck %s -check-prefix=PERSONTYPE-DOT-OPT-SPACE + +class Person { + var name: String + var friends: [Person] = [] + var bestFriend: Person? = nil + var itself: Person { return self } + init(name: String) { + self.name = name + } + func getName() -> String { return name } + subscript(_ index: Int) -> Int { get { return 1} } +} + +extension Optional { + var optMember: String { "member" } +} + +let _ : KeyPath = \.#^TYPE_INFER_DOT_OPTIONAL^# +// PERSONTYPE-INFER-DOT-OPT: Begin completions, 9 items +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.name[#String#]; name=name +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.friends[#[Person]#]; name=friends +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.bestFriend[#Person?#]; name=bestFriend +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.itself[#Person#]; name=itself +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[Subscript]/CurrNominal: ?[{#(index): Int#}][#Int#]; name=[index: Int] +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: optMember[#String#]; name=optMember +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: debugDescription[#String#]; name=debugDescription +// PERSONTYPE-INFER-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: customMirror[#Mirror#]; name=customMirror + +let _ : KeyPath = \Person?.#^TYPE_DOT_OPTIONAL^# +// PERSONTYPE-DOT-OPT: Begin completions, 9 items +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.name[#String#]; name=name +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.friends[#[Person]#]; name=friends +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.bestFriend[#Person?#]; name=bestFriend +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: ?.itself[#Person#]; name=itself +// PERSONTYPE-DOT-OPT-NEXT: Decl[Subscript]/CurrNominal: ?[{#(index): Int#}][#Int#]; name=[index: Int] +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal: optMember[#String#]; name=optMember +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: debugDescription[#String#]; name=debugDescription +// PERSONTYPE-DOT-OPT-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: customMirror[#Mirror#]; name=customMirror + +let _ : KeyPath = \Person?. #^TYPE_DOT_OPTIONAL_SPACE^# +// PERSONTYPE-DOT-OPT-SPACE: Begin completions, 9 items +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.name[#String#]; name=name +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.friends[#[Person]#]; name=friends +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.bestFriend[#Person?#]; name=bestFriend +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.itself[#Person#]; name=itself +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[Subscript]/CurrNominal/Erase[1]: ?[{#(index): Int#}][#Int#]; name=[index: Int] +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal: optMember[#String#]; name=optMember +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: debugDescription[#String#]; name=debugDescription +// PERSONTYPE-DOT-OPT-SPACE-NEXT: Decl[InstanceVar]/CurrNominal/IsSystem: customMirror[#Mirror#]; name=customMirror From aee9578702a6a9147863175e65421941e5679ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Wed, 26 Aug 2020 17:49:27 -0700 Subject: [PATCH 495/663] [Sema] Make getDisallowedOriginKind usable to other source files --- lib/Sema/TypeCheckAccess.cpp | 72 ++++++++++++++++++------------------ lib/Sema/TypeCheckAccess.h | 21 +++++++++++ 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 8f2556c311a85..ed25d52e2180a 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1454,47 +1454,40 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, } }; +/// Returns the kind of origin, implementation-only import or SPI declaration, +/// that restricts exporting \p decl from the given file and context. +/// +/// Local variant to swift::getDisallowedOriginKind for downgrade to warnings. +DisallowedOriginKind +getDisallowedOriginKind(const Decl *decl, + const SourceFile &userSF, + const Decl *userContext, + DowngradeToWarning &downgradeToWarning) { + downgradeToWarning = DowngradeToWarning::No; + ModuleDecl *M = decl->getModuleContext(); + if (userSF.isImportedImplementationOnly(M)) { + // Temporarily downgrade implementation-only exportability in SPI to + // a warning. + if (userContext->isSPI()) + downgradeToWarning = DowngradeToWarning::Yes; + + // Implementation-only imported, cannot be reexported. + return DisallowedOriginKind::ImplementationOnly; + } else if (decl->isSPI() && !userContext->isSPI()) { + // SPI can only be exported in SPI. + return userContext->getModuleContext() == M ? + DisallowedOriginKind::SPILocal : + DisallowedOriginKind::SPIImported; + } + + return DisallowedOriginKind::None; +}; + // Diagnose public APIs exposing types that are either imported as // implementation-only or declared as SPI. class ExportabilityChecker : public DeclVisitor { class Diagnoser; - // Problematic origin of an exported type. - // - // This enum must be kept in sync with - // diag::decl_from_hidden_module and - // diag::conformance_from_implementation_only_module. - enum class DisallowedOriginKind : uint8_t { - ImplementationOnly, - SPIImported, - SPILocal, - None - }; - - // If there's an exportability problem with \p typeDecl, get its origin kind. - static DisallowedOriginKind getDisallowedOriginKind( - const TypeDecl *typeDecl, const SourceFile &SF, const Decl *context, - DowngradeToWarning &downgradeToWarning) { - downgradeToWarning = DowngradeToWarning::No; - ModuleDecl *M = typeDecl->getModuleContext(); - if (SF.isImportedImplementationOnly(M)) { - // Temporarily downgrade implementation-only exportability in SPI to - // a warning. - if (context->isSPI()) - downgradeToWarning = DowngradeToWarning::Yes; - - // Implementation-only imported, cannot be reexported. - return DisallowedOriginKind::ImplementationOnly; - } else if (typeDecl->isSPI() && !context->isSPI()) { - // SPI can only be exported in SPI. - return context->getModuleContext() == M ? - DisallowedOriginKind::SPILocal : - DisallowedOriginKind::SPIImported; - } - - return DisallowedOriginKind::None; - }; - void checkTypeImpl( Type type, const TypeRepr *typeRepr, const SourceFile &SF, const Decl *context, @@ -2067,6 +2060,13 @@ static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) { ED, ED, desiredAccessScope, userSpecifiedAccess); } +DisallowedOriginKind swift::getDisallowedOriginKind(const Decl *decl, + const SourceFile &userSF, + const Decl *declContext) { + auto downgradeToWarning = DowngradeToWarning::No; + return getDisallowedOriginKind(decl, userSF, declContext, downgradeToWarning); +} + void swift::checkAccessControl(Decl *D) { if (isa(D) || isa(D)) { AccessControlChecker().visit(D); diff --git a/lib/Sema/TypeCheckAccess.h b/lib/Sema/TypeCheckAccess.h index 181fb4490a301..d29523ef39a8d 100644 --- a/lib/Sema/TypeCheckAccess.h +++ b/lib/Sema/TypeCheckAccess.h @@ -17,9 +17,12 @@ #ifndef TYPECHECKACCESS_H #define TYPECHECKACCESS_H +#include + namespace swift { class Decl; +class SourceFile; /// Performs access-related checks for \p D. /// @@ -28,6 +31,24 @@ class Decl; /// itself. Related checks may also be performed. void checkAccessControl(Decl *D); +// Problematic origin of an exported type. +// +// This enum must be kept in sync with +// diag::decl_from_hidden_module and +// diag::conformance_from_implementation_only_module. +enum class DisallowedOriginKind : uint8_t { + ImplementationOnly, + SPIImported, + SPILocal, + None +}; + +/// Returns the kind of origin, implementation-only import or SPI declaration, +/// that restricts exporting \p decl from the given file and context. +DisallowedOriginKind getDisallowedOriginKind(const Decl *decl, + const SourceFile &userSF, + const Decl *userContext); + } // end namespace swift #endif From 3acbd0917eb7dcd29d7e2dd0b5f655c3e3d070b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Tue, 18 Aug 2020 09:28:02 -0700 Subject: [PATCH 496/663] [Sema] Type-check exportability of SPI conformances Report the use of conformances declared as SPI in public declarations and inlinable code. rdar://problem/66659715 --- include/swift/AST/DiagnosticsSema.def | 14 +- lib/Sema/ResilienceDiagnostics.cpp | 29 +- lib/Sema/TypeCheckAccess.cpp | 14 +- lib/Sema/TypeCheckProtocol.cpp | 24 +- test/SPI/protocol_requirement.swift | 17 ++ test/Sema/spi-in-decls.swift | 307 +++++++++++++++++++++ test/Sema/spi-inlinable-conformances.swift | 294 ++++++++++++++++++++ 7 files changed, 664 insertions(+), 35 deletions(-) create mode 100644 test/Sema/spi-in-decls.swift create mode 100644 test/Sema/spi-inlinable-conformances.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index beaf7b6ea3dd5..73c7e60356f2c 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2726,13 +2726,17 @@ WARNING(decl_from_hidden_module_warn,none, ERROR(conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 %select{here|as property wrapper here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances}2; %3 has been imported " - "as implementation-only", - (Type, Identifier, unsigned, Identifier)) + "in an extension with conditional conformances}2; " + "%select{%3 has been imported as implementation-only|" + "the conformance is declared as SPI in %3|" + "the conformance is declared as SPI}4", + (Type, Identifier, unsigned, Identifier, unsigned)) ERROR(assoc_conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 in associated type %3 (inferred as " - "%4); %2 has been imported as implementation-only", - (Type, Identifier, Identifier, Type, Type)) + "%4); %select{%2 has been imported as implementation-only|" + "the conformance is declared as SPI in %2|" + "the conformance is declared as SPI}5", + (Type, Identifier, Identifier, Type, Type, unsigned)) ERROR(unexportable_clang_function_type,none, "cannot export the underlying C type of the function type %0; " "it may use anonymous types or types defined outside of a module", diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index ee8cf299ed2dc..8da9fd07da9ab 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -16,6 +16,7 @@ #include "TypeChecker.h" #include "TypeCheckAvailability.h" +#include "TypeCheckAccess.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" @@ -171,7 +172,8 @@ static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D, static bool diagnoseGenericArgumentsExportability(SourceLoc loc, SubstitutionMap subs, - const SourceFile &userSF) { + const SourceFile &userSF, + const DeclContext *userDC) { bool hadAnyIssues = false; for (ProtocolConformanceRef conformance : subs.getConformances()) { if (!conformance.isConcrete()) @@ -180,18 +182,23 @@ diagnoseGenericArgumentsExportability(SourceLoc loc, SubstitutionMap subConformanceSubs = concreteConf->getSubstitutions(userSF.getParentModule()); - diagnoseGenericArgumentsExportability(loc, subConformanceSubs, userSF); + diagnoseGenericArgumentsExportability(loc, subConformanceSubs, userSF, userDC); const RootProtocolConformance *rootConf = concreteConf->getRootConformance(); ModuleDecl *M = rootConf->getDeclContext()->getParentModule(); - if (!userSF.isImportedImplementationOnly(M)) + + auto originKind = getDisallowedOriginKind( + rootConf->getDeclContext()->getAsDecl(), + userSF, userDC->getInnermostDeclarationDeclContext()); + if (originKind == DisallowedOriginKind::None) continue; ASTContext &ctx = M->getASTContext(); ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module, rootConf->getType(), - rootConf->getProtocol()->getName(), 0, M->getName()); + rootConf->getProtocol()->getName(), 0, M->getName(), + static_cast(originKind)); hadAnyIssues = true; } return hadAnyIssues; @@ -209,10 +216,10 @@ void TypeChecker::diagnoseGenericTypeExportability(SourceLoc Loc, Type T, if (auto *BGT = dyn_cast(T.getPointer())) { ModuleDecl *useModule = SF->getParentModule(); auto subs = T->getContextSubstitutionMap(useModule, BGT->getDecl()); - (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF); + (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF, DC); } else if (auto *TAT = dyn_cast(T.getPointer())) { auto subs = TAT->getSubstitutionMap(); - (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF); + (void)diagnoseGenericArgumentsExportability(Loc, subs, *SF, DC); } } @@ -226,19 +233,11 @@ TypeChecker::diagnoseDeclRefExportability(SourceLoc loc, if (!userSF) return false; - // If the source file doesn't have any implementation-only imports, - // we can fast-path this. In the current language design, we never - // need to consider the possibility of implementation-only imports - // from other source files in the module (or indirectly in other modules). - // TODO: maybe check whether D is from a bridging header? - if (!userSF->hasImplementationOnlyImports()) - return false; - const ValueDecl *D = declRef.getDecl(); if (diagnoseDeclExportability(loc, D, *userSF, fragileKind)) return true; if (diagnoseGenericArgumentsExportability(loc, declRef.getSubstitutions(), - *userSF)) { + *userSF, DC)) { return true; } return false; diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index ed25d52e2180a..67f15ea3f539b 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1553,10 +1553,12 @@ class ExportabilityChecker : public DeclVisitor { const RootProtocolConformance *rootConf = concreteConf->getRootConformance(); - ModuleDecl *M = rootConf->getDeclContext()->getParentModule(); - if (!SF.isImportedImplementationOnly(M)) + auto originKind = getDisallowedOriginKind( + rootConf->getDeclContext()->getAsDecl(), + SF, context); + if (originKind == DisallowedOriginKind::None) continue; - diagnoser.diagnoseConformance(rootConf); + diagnoser.diagnoseConformance(rootConf, originKind); } } @@ -1667,12 +1669,14 @@ class ExportabilityChecker : public DeclVisitor { highlightOffendingType(diag, complainRepr); } - void diagnoseConformance(const ProtocolConformance *offendingConformance) const { + void diagnoseConformance(const ProtocolConformance *offendingConformance, + DisallowedOriginKind originKind) const { ModuleDecl *M = offendingConformance->getDeclContext()->getParentModule(); D->diagnose(diag::conformance_from_implementation_only_module, offendingConformance->getType(), offendingConformance->getProtocol()->getName(), - static_cast(reason), M->getName()); + static_cast(reason), M->getName(), + static_cast(originKind)); } void diagnoseClangFunctionType(Type fnType, const clang::Type *type) const { diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index b3b57e5dc8fa9..60b25436f0c3a 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -19,6 +19,7 @@ #include "DerivedConformances.h" #include "MiscDiagnostics.h" #include "TypeAccessScopeChecker.h" +#include "TypeCheckAccess.h" #include "TypeCheckAvailability.h" #include "TypeCheckObjC.h" #include "swift/AST/ASTContext.h" @@ -4039,7 +4040,8 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( static void checkExportability(Type depTy, Type replacementTy, const ProtocolConformance *conformance, NormalProtocolConformance *conformanceBeingChecked, - SourceFile *SF) { + DeclContext *DC) { + SourceFile *SF = DC->getParentSourceFile(); if (!SF) return; @@ -4049,13 +4051,17 @@ static void checkExportability(Type depTy, Type replacementTy, if (!subConformance.isConcrete()) continue; checkExportability(depTy, replacementTy, subConformance.getConcrete(), - conformanceBeingChecked, SF); + conformanceBeingChecked, DC); } const RootProtocolConformance *rootConformance = conformance->getRootConformance(); ModuleDecl *M = rootConformance->getDeclContext()->getParentModule(); - if (!SF->isImportedImplementationOnly(M)) + + auto originKind = getDisallowedOriginKind( + rootConformance->getDeclContext()->getAsDecl(), + *SF, DC->getAsDecl()); + if (originKind == DisallowedOriginKind::None) return; ASTContext &ctx = SF->getASTContext(); @@ -4066,14 +4072,16 @@ static void checkExportability(Type depTy, Type replacementTy, conformanceBeingChecked->getLoc(), diag::conformance_from_implementation_only_module, rootConformance->getType(), - rootConformance->getProtocol()->getName(), 0, M->getName()); + rootConformance->getProtocol()->getName(), 0, M->getName(), + static_cast(originKind)); } else { ctx.Diags.diagnose( conformanceBeingChecked->getLoc(), diag::assoc_conformance_from_implementation_only_module, rootConformance->getType(), rootConformance->getProtocol()->getName(), M->getName(), - depTy, replacementTy->getCanonicalType()); + depTy, replacementTy->getCanonicalType(), + static_cast(originKind)); } } @@ -4122,11 +4130,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() { // Now check that our associated conformances are at least as visible as // the conformance itself. - // - // FIXME: Do we need to check SPI here too? if (getRequiredAccessScope().isPublic() || isUsableFromInlineRequired()) { - auto *fileForCheckingExportability = DC->getParentSourceFile(); - for (auto req : proto->getRequirementSignature()) { if (req.getKind() == RequirementKind::Conformance) { auto depTy = req.getFirstType(); @@ -4136,7 +4140,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() { auto *concrete = conformance.getConcrete(); auto replacementTy = DC->mapTypeIntoContext(concrete->getType()); checkExportability(depTy, replacementTy, concrete, - Conformance, fileForCheckingExportability); + Conformance, DC); } } } diff --git a/test/SPI/protocol_requirement.swift b/test/SPI/protocol_requirement.swift index 756915e1556ee..c3b952e1c8221 100644 --- a/test/SPI/protocol_requirement.swift +++ b/test/SPI/protocol_requirement.swift @@ -96,3 +96,20 @@ public protocol SPIProtocol { @_spi(Private) static var staticProperty: Int { get } } + +public protocol OtherProto {} +public protocol Proto { + associatedtype A : Sequence where A.Element : OtherProto +} + +public struct BadStruct {} +@_spi(Horse) extension BadStruct : OtherProto {} +public struct BadConforms : Proto { // expected-error {{cannot use conformance of 'BadStruct' to 'OtherProto' in associated type 'Self.A.Element' (inferred as 'BadStruct'); the conformance is declared as SPI}} + public typealias A = [BadStruct] +} + +public struct OKStruct {} +@_spi(Horse) extension OKStruct : OtherProto {} +@_spi(Horse) public struct OKConforms : Proto { + public typealias A = [OKStruct] +} diff --git a/test/Sema/spi-in-decls.swift b/test/Sema/spi-in-decls.swift new file mode 100644 index 0000000000000..e83c88a7cc660 --- /dev/null +++ b/test/Sema/spi-in-decls.swift @@ -0,0 +1,307 @@ +/// SPI variant of implementation-only-import-in-decls with the "Bad" +/// declarations defined as local SPI. + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule %S/Inputs/implementation-only-import-in-decls-public-helper.swift + +// RUN: %target-typecheck-verify-swift -I %t + +import NormalLibrary + +@_spi(X) +extension NormalStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension GenericStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension NormalClass: NormalProto { + public typealias Assoc = Int +} + +@_spi(X) +public struct BadStruct {} // expected-note 27 {{type declared here}} +@_spi(X) +public protocol BadProto {} // expected-note 20 {{type declared here}} +@_spi(X) +open class BadClass {} // expected-note 2 {{type declared here}} + +@_spi(X) +public struct IntLike: ExpressibleByIntegerLiteral, Equatable { // expected-note {{type declared here}} + public init(integerLiteral: Int) {} +} + +@_spi(X) +@propertyWrapper +public struct BadWrapper { // expected-note {{type declared here}} + public var wrappedValue: Int + public init(wrappedValue: Int) { + self.wrappedValue = wrappedValue + } +} + +// FIXME SPI precedencegroups are not yet accepted. +//@_spi(X) +//precedencegroup BadPrecedence {} + +public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +struct TestConformanceOkay: BadProto {} // ok + +public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + + +public struct TestGenericParams {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public struct TestGenericParamsWhereClause where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public enum TestCase { + case x(BadStruct) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + case y(Int, BadStruct) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public func testGenericParams(_: T) {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public func testGenericParamsWhereClause(_: T) where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public func testParams(_: BadStruct, _: BadProto) {} +// expected-error@-1 {{cannot use struct 'BadStruct' here; it is SPI}} +// expected-error@-2 {{cannot use protocol 'BadProto' here; it is SPI}} +public func testResult() -> BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + +public struct TestSubscript { + public subscript(_: T) -> Int { return 0 } // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + public subscript(where _: T) -> Int where T: BadProto { return 0 } // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + public subscript(_: BadStruct) -> Int { return 0 } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + public subscript(_: Int) -> BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public struct TestInit { + public init(_: BadStruct) {} // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + public init(_: T) {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + public init(where _: T) where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +} + +public struct TestPropertyWrapper { + @BadWrapper public var BadProperty: Int // expected-error {{cannot use struct 'BadWrapper' as property wrapper here; it is SPI}} +} + +public protocol TestInherited: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public protocol TestConstraintBase { + associatedtype Assoc +} +public protocol TestConstraint: TestConstraintBase where Assoc: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +public protocol TestConstraintEq: TestConstraintBase where Assoc == BadStruct {} // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + +public protocol TestAssocType { + associatedtype Assoc: BadProto // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +} + +public protocol TestAssocTypeWhereClause { + associatedtype Assoc: Collection where Assoc.Element: BadProto // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +} + +public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' here; it is SPI}} + case x = 1 + // FIXME: expected-error@-1 {{cannot use conformance of 'IntLike' to 'Equatable' here; the conformance is declared as SPI}} +} + +public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' here; it is SPI}} +} + +public typealias TestUnderlying = BadStruct // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public typealias TestGenericParamsAliasWhereClause = T where T: BadProto // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public typealias TestGenericParamsAlias = T // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} + +public var testBadType: BadStruct? = nil // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testBadTypeInferred = Optional.none // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testBadTypePartiallyInferred: Optional = Optional.none // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var (testBadTypeTuple1, testBadTypeTuple2): (BadStruct?, BadClass?) = (nil, nil) +// expected-error@-1 {{cannot use struct 'BadStruct' here; it is SPI}} +// expected-error@-2 {{cannot use class 'BadClass' here; it is SPI}} +public var (testBadTypeTuplePartlyInferred1, testBadTypeTuplePartlyInferred2): (Optional, Optional) = (Optional.none, Optional.none) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var (testBadTypeTuplePartlyInferred3, testBadTypeTuplePartlyInferred4): (Optional, Optional) = (Optional.none, Optional.none) // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testMultipleBindings1: Int? = nil, testMultipleBindings2: BadStruct? = nil // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +public var testMultipleBindings3: BadStruct? = nil, testMultipleBindings4: Int? = nil // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + +extension BadStruct { + public func testExtensionOfBadType() {} + public var testExtensionVarBad: Int { 0 } + public subscript(bad _: Int) -> Int { 0 } + + func testExtensionOfOkayType() {} + var testExtensionVarOkay: Int { 0 } + subscript(okay _: Int) -> Int { 0 } +} + +extension Array where Element == BadStruct { // expected-error {{cannot use struct 'BadStruct' in an extension with public or '@usableFromInline' members; it is SPI}} + public func testExtensionWithBadRequirement() {} + public var testExtensionVarBad: Int { 0 } + public subscript(bad _: Int) -> Int { 0 } +} + +extension Array where Element == BadStruct { + func testExtensionWithOkayRequirement() {} // okay + var testExtensionVarOkay: Int { 0 } // okay + subscript(okay _: Int) -> Int { 0 } // okay +} + +extension Int: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; it is SPI}} +struct TestExtensionConformanceOkay {} +extension TestExtensionConformanceOkay: BadProto {} // okay + +public protocol TestConstrainedExtensionProto {} +extension Array: TestConstrainedExtensionProto where Element == BadStruct { // expected-error {{cannot use struct 'BadStruct' in an extension with conditional conformances; it is SPI}} +} + + +// FIXME Support SPI precedencegroup? +//infix operator !!!!!!: BadPrecedence +// +//precedencegroup TestLowerThan { +// lowerThan: BadPrecedence +//} +//precedencegroup TestHigherThan { +// higherThan: BadPrecedence +//} + +public struct PublicStructStoredProperties { + public var publiclyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + internal var internallyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private var privatelyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private let letIsLikeVar = [BadStruct]() // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + + private var computedIsOkay: BadStruct? { return nil } // okay + private static var staticIsOkay: BadStruct? // okay + @usableFromInline internal var computedUFIIsNot: BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +@usableFromInline internal struct UFIStructStoredProperties { + @usableFromInline var publiclyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + internal var internallyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private var privatelyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private let letIsLikeVar = [BadStruct]() // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + + private var computedIsOkay: BadStruct? { return nil } // okay + private static var staticIsOkay: BadStruct? // okay + @usableFromInline internal var computedUFIIsNot: BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public class PublicClassStoredProperties { + public var publiclyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + internal var internallyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private var privatelyBad: BadStruct? // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + private let letIsLikeVar = [BadStruct]() // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} + + private var computedIsOkay: BadStruct? { return nil } // okay + private static var staticIsOkay: BadStruct? // okay + @usableFromInline internal var computedUFIIsNot: BadStruct? { return nil } // expected-error {{cannot use struct 'BadStruct' here; it is SPI}} +} + +public typealias NormalProtoAssoc = T.Assoc +public func testConformanceInTypealias(_: NormalProtoAssoc) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public struct NormalProtoAssocHolder { + public var value: T.Assoc +} +public func testConformanceInBoundGeneric(_: NormalProtoAssocHolder) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public class SubclassOfNormalClass: NormalClass {} + +public func testInheritedConformance(_: NormalProtoAssocHolder) {} // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' here; the conformance is declared as SPI}} +public func testSpecializedConformance(_: NormalProtoAssocHolder>) {} // expected-error {{cannot use conformance of 'GenericStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +extension Array where Element == NormalProtoAssocHolder { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in an extension with public or '@usableFromInline' members; the conformance is declared as SPI}} + public func testConstrainedExtensionUsingBadConformance() {} +} + +public struct ConditionalGenericStruct {} +extension ConditionalGenericStruct: NormalProto where T: NormalProto { + public typealias Assoc = Int +} +public func testConditionalGeneric(_: NormalProtoAssocHolder>) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public protocol PublicAssociatedTypeProto { + associatedtype Assoc: NormalProto + func takesAssoc(_: Assoc) +} +@usableFromInline protocol UFIAssociatedTypeProto { + associatedtype Assoc: NormalProto + func takesAssoc(_: Assoc) +} +protocol InternalAssociatedTypeProto { + associatedtype Assoc: NormalProto + func takesAssoc(_: Assoc) +} + +public struct PublicInferredAssociatedTypeImpl { + public func takesAssoc(_: NormalStruct) {} +} +extension PublicInferredAssociatedTypeImpl: PublicAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicInferredAssociatedTypeImpl: UFIAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicInferredAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + +@usableFromInline struct UFIInferredAssociatedTypeImpl { + public func takesAssoc(_: NormalStruct) {} +} +extension UFIInferredAssociatedTypeImpl: PublicAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension UFIInferredAssociatedTypeImpl: UFIAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension UFIInferredAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + +struct InternalInferredAssociatedTypeImpl { + public func takesAssoc(_: NormalStruct) {} +} +extension InternalInferredAssociatedTypeImpl: PublicAssociatedTypeProto {} // okay +extension InternalInferredAssociatedTypeImpl: UFIAssociatedTypeProto {} // okay +extension InternalInferredAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + +public struct PublicExplicitAssociatedTypeImpl { + public typealias Assoc = NormalStruct + public func takesAssoc(_: NormalStruct) {} +} +extension PublicExplicitAssociatedTypeImpl: PublicAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicExplicitAssociatedTypeImpl: UFIAssociatedTypeProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} +extension PublicExplicitAssociatedTypeImpl: InternalAssociatedTypeProto {} // okay + + +public protocol BaseProtoWithNoRequirement { + associatedtype Assoc + func takesAssoc(_: Assoc) +} +public protocol RefinedProto: BaseProtoWithNoRequirement where Assoc: NormalProto { +} + +public struct RefinedProtoImpl: RefinedProto { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); the conformance is declared as SPI}} + public func takesAssoc(_: NormalStruct) {} +} + +public protocol RefinedSelfProto where Self: NormalProto {} +extension NormalStruct: RefinedSelfProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public protocol RefinedSelfProtoInheritance: NormalProto {} +extension NormalStruct: RefinedSelfProtoInheritance {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + +public protocol SlightlyMoreComplicatedRequirement { + associatedtype Assoc: Collection where Assoc.Element: NormalProto + func takesAssoc(_: Assoc) +} +public struct SlightlyMoreComplicatedRequirementImpl: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'NormalStruct'); the conformance is declared as SPI}} + public func takesAssoc(_: [NormalStruct]) {} +} +public struct RequirementsHandleSubclassesToo: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'SubclassOfNormalClass'); the conformance is declared as SPI}} + public func takesAssoc(_: [SubclassOfNormalClass]) {} +} + +public struct RequirementsHandleSpecializationsToo: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'ConditionalGenericStruct'); the conformance is declared as SPI}} + public func takesAssoc(_: [ConditionalGenericStruct]) {} +} + +public struct ClassConstrainedGenericArg: PublicAssociatedTypeProto { // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'T'); the conformance is declared as SPI}} + public func takesAssoc(_: T) {} +} diff --git a/test/Sema/spi-inlinable-conformances.swift b/test/Sema/spi-inlinable-conformances.swift new file mode 100644 index 0000000000000..cd7a861272095 --- /dev/null +++ b/test/Sema/spi-inlinable-conformances.swift @@ -0,0 +1,294 @@ +/// SPI variant of implementation-only-inlinable-conformances with the "Bad" +/// declarations defined as local SPI. Also check that SPI conformances +/// can be used within inlinable SPI decls. + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule %S/Inputs/implementation-only-import-in-decls-public-helper.swift + +// RUN: %target-typecheck-verify-swift -I %t + +import NormalLibrary + +@_spi(X) +extension NormalStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension GenericStruct: NormalProto { + public typealias Assoc = Int +} +@_spi(X) +extension NormalClass: NormalProto { + public typealias Assoc = Int +} + +@_spi(X) +public struct BadStruct {} +@_spi(X) +public protocol BadProto {} +@_spi(X) +open class BadClass {} + +@_spi(X) +public struct IntLike: ExpressibleByIntegerLiteral, Equatable { + public init(integerLiteral: Int) {} +} + +@available(*, unavailable) +public typealias X = Int + +public typealias NormalProtoAssoc = T.Assoc +@inlinable func testConformanceInTypealias() { + let x: NormalProtoAssoc? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = x + _ = NormalProtoAssoc() // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestConformanceInTypealias() { + let x: NormalProtoAssoc? = nil + _ = x + _ = NormalProtoAssoc() +} + +func internalConformanceInTypealias() { + let x: NormalProtoAssoc? = nil // okay + _ = x + _ = NormalProtoAssoc() // okay +} + +public struct NormalProtoAssocHolder { + public var value: T.Assoc? + public init() {} + public init(_ value: T?) {} +} +@inlinable func testConformanceInBoundGeneric() { + let x: NormalProtoAssocHolder? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = x + // FIXME: We get this error twice: once for the TypeExpr and once for the implicit init. + _ = NormalProtoAssocHolder() // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestConformanceInBoundGeneric() { + let x: NormalProtoAssocHolder? = nil + _ = x + _ = NormalProtoAssocHolder() + _ = NormalProtoAssocHolder(nil as NormalStruct?) +} + +func internalConformanceInBoundGeneric() { + let x: NormalProtoAssocHolder? = nil // okay + _ = x + _ = NormalProtoAssocHolder() // okay + _ = NormalProtoAssocHolder(nil as NormalStruct?) // okay +} + +@inlinable func testDowncast(_ x: Any) -> Bool { + let normal = x is NormalProtoAssocHolder // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let alias = x is NormalProtoAssoc // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + return normal || alias +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestDowncast(_ x: Any) -> Bool { + let normal = x is NormalProtoAssocHolder + let alias = x is NormalProtoAssoc + return normal || alias +} + +func internalDowncast(_ x: Any) -> Bool { + let normal = x is NormalProtoAssocHolder // okay + let alias = x is NormalProtoAssoc // okay + return normal || alias +} + +@inlinable func testSwitch(_ x: Any) { + switch x { + case let holder as NormalProtoAssocHolder: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = holder + break + case is NormalProtoAssoc: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + break + default: + break + } +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestSwitch(_ x: Any) { + switch x { + case let holder as NormalProtoAssocHolder: + _ = holder + break + case is NormalProtoAssoc: + break + default: + break + } +} + +func internalSwitch(_ x: Any) { + switch x { + case let holder as NormalProtoAssocHolder: // okay + _ = holder + break + case is NormalProtoAssoc: // okay + break + default: + break + } +} + +public enum NormalProtoEnumUser { + case a +} + +@inlinable func testEnum() { + // FIXME: We get this error twice: once for the pattern and once for the implicit TypeExpr. + let x: NormalProtoEnumUser = .a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = x + // FIXME: We get this error twice: once for the TypeExpr and once for the case. + _ = NormalProtoEnumUser.a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestEnum() { + let x: NormalProtoEnumUser = .a + _ = x + _ = NormalProtoEnumUser.a +} + +func internalEnum() { + let x: NormalProtoEnumUser = .a // okay + _ = x + _ = NormalProtoEnumUser.a // okay +} + +@usableFromInline func testFuncImpl(_: T.Type) {} + +@inlinable func testFunc() { + testFuncImpl(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestFunc() { + testFuncImpl(NormalStruct.self) +} + +func internalFunc() { + testFuncImpl(NormalStruct.self) // okay +} + +public struct ForTestingMembers { + public init() {} + public init(_: T.Type) {} + + public subscript(_: T.Type) -> Int { + get { return 0 } + set {} + } + + public func method(_: T.Type) {} +} + +@inlinable func testMembers() { + _ = ForTestingMembers(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + _ = ForTestingMembers.init(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + _ = ForTestingMembers()[NormalStruct.self] // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + var instance = ForTestingMembers() + instance[NormalStruct.self] = 1 // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + ForTestingMembers().method(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestMembers() { + _ = ForTestingMembers(NormalStruct.self) + _ = ForTestingMembers.init(NormalStruct.self) + + _ = ForTestingMembers()[NormalStruct.self] + var instance = ForTestingMembers() + instance[NormalStruct.self] = 1 + + ForTestingMembers().method(NormalStruct.self) +} + +extension NormalProtoAssocHolder { + public static func testAnotherConformance(_: U.Type) {} +} + +@inlinable func testMultipleConformances() { + NormalProtoAssocHolder.testAnotherConformance(NormalClass.self) + // expected-error@-1 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + // expected-error@-2 {{cannot use conformance of 'NormalClass' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestMultipleConformances() { + NormalProtoAssocHolder.testAnotherConformance(NormalClass.self) +} + +@inlinable func localTypeAlias() { + typealias LocalUser = NormalProtoAssocHolder // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + typealias LocalGenericUser = (T, NormalProtoAssocHolder) // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + typealias LocalProtoAssoc = T.Assoc + _ = LocalProtoAssoc() // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPIlocalTypeAlias() { + // FIXME these should be accepted. + typealias LocalUser = NormalProtoAssocHolder // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + typealias LocalGenericUser = (T, NormalProtoAssocHolder) // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + + typealias LocalProtoAssoc = T.Assoc + _ = LocalProtoAssoc() +} + +@inlinable func localFunctions() { + func local(_: NormalProtoAssocHolder) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + func localReturn() -> NormalProtoAssocHolder { fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let _ = { (_: NormalProtoAssocHolder) in return } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let _ = { () -> NormalProtoAssocHolder in fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPIlocalFunctions() { + // FIXME these should be accepted. + func local(_: NormalProtoAssocHolder) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + func localReturn() -> NormalProtoAssocHolder { fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + let _ = { (_: NormalProtoAssocHolder) in return } + let _ = { () -> NormalProtoAssocHolder in fatalError() } +} + +@inlinable public func signatureOfInlinable(_: NormalProtoAssocHolder) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +public func testDefaultArgument(_: Int = NormalProtoAssoc()) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; the conformance is declared as SPI}} + +@_spi(AcceptInSPI) +@inlinable public func SPIsignatureOfInlinable(_: NormalProtoAssocHolder) {} + +@_spi(AcceptInSPI) +public func SPItestDefaultArgument(_: Int = NormalProtoAssoc()) {} + +public class SubclassOfNormalClass: NormalClass {} + +@inlinable public func testInheritedConformance() { + _ = NormalProtoAssocHolder.self // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' here; the conformance is declared as SPI}} +} +@inlinable public func testSpecializedConformance() { + _ = NormalProtoAssocHolder>.self // expected-error {{cannot use conformance of 'GenericStruct' to 'NormalProto' here; the conformance is declared as SPI}} +} + +@_spi(AcceptInSPI) +@inlinable public func SPItestInheritedConformance() { + _ = NormalProtoAssocHolder.self +} +@_spi(AcceptInSPI) +@inlinable public func SPItestSpecializedConformance() { + _ = NormalProtoAssocHolder>.self +} From 1bfb0b074765e1aa44525d3c3519d5e7051c5fee Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Sep 2020 12:23:47 -0700 Subject: [PATCH 497/663] [ConstraintSystem] Extend invalid function body fix to cover constraint generation failures Ignore function builder body if it emits at least one diagnostic during constraint generation. Resolves: rdar://problem/65983237 --- lib/Sema/BuilderTransform.cpp | 22 ++++++++++++++++++---- lib/Sema/CSFix.cpp | 16 ++++++++++++---- lib/Sema/CSFix.h | 27 +++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index c4a1dd048911f..7c35c1250db80 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1669,7 +1669,7 @@ ConstraintSystem::matchFunctionBuilder( if (!shouldAttemptFixes()) return getTypeMatchFailure(locator); - if (recordFix(IgnoreInvalidFunctionBuilderBody::create( + if (recordFix(IgnoreInvalidFunctionBuilderBody::duringPreCheck( *this, getConstraintLocator(fn.getBody())))) return getTypeMatchFailure(locator); @@ -1711,9 +1711,23 @@ ConstraintSystem::matchFunctionBuilder( BuilderClosureVisitor visitor(getASTContext(), this, dc, builderType, bodyResultType); - auto applied = visitor.apply(fn.getBody()); - if (!applied) - return getTypeMatchFailure(locator); + Optional applied = None; + { + DiagnosticTransaction transaction(dc->getASTContext().Diags); + + applied = visitor.apply(fn.getBody()); + if (!applied) + return getTypeMatchFailure(locator); + + if (transaction.hasDiagnostics()) { + if (recordFix( + IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration( + *this, getConstraintLocator(fn.getBody())))) + return getTypeMatchFailure(locator); + + return getTypeMatchSuccess(); + } + } Type transformedType = getType(applied->returnExpr); assert(transformedType && "Missing type"); diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 80cc9fc225ad6..8dd90f0f9ca8d 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1554,6 +1554,14 @@ AllowKeyPathWithoutComponents::create(ConstraintSystem &cs, bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, bool asNote) const { + switch (Phase) { + // Handled below + case ErrorInPhase::PreCheck: + break; + case ErrorInPhase::ConstraintGeneration: + return true; // Already diagnosed by `matchFunctionBuilder`. + } + auto *S = getAnchor().get(); class PreCheckWalker : public ASTWalker { @@ -1590,8 +1598,8 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, return walker.diagnosed(); } -IgnoreInvalidFunctionBuilderBody * -IgnoreInvalidFunctionBuilderBody::create(ConstraintSystem &cs, - ConstraintLocator *locator) { - return new (cs.getAllocator()) IgnoreInvalidFunctionBuilderBody(cs, locator); +IgnoreInvalidFunctionBuilderBody *IgnoreInvalidFunctionBuilderBody::create( + ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator) { + return new (cs.getAllocator()) + IgnoreInvalidFunctionBuilderBody(cs, phase, locator); } diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 7bcaf50f85c65..d4150e5be9dd8 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -1984,9 +1984,17 @@ class AllowKeyPathWithoutComponents final : public ConstraintFix { }; class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix { - IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs, + enum class ErrorInPhase { + PreCheck, + ConstraintGeneration, + }; + + ErrorInPhase Phase; + + IgnoreInvalidFunctionBuilderBody(ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator) - : ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator) {} + : ConstraintFix(cs, FixKind::IgnoreInvalidFunctionBuilderBody, locator), + Phase(phase) {} public: std::string getName() const override { @@ -1999,8 +2007,19 @@ class IgnoreInvalidFunctionBuilderBody final : public ConstraintFix { return diagnose(*commonFixes.front().first); } - static IgnoreInvalidFunctionBuilderBody *create(ConstraintSystem &cs, - ConstraintLocator *locator); + static IgnoreInvalidFunctionBuilderBody * + duringPreCheck(ConstraintSystem &cs, ConstraintLocator *locator) { + return create(cs, ErrorInPhase::PreCheck, locator); + } + + static IgnoreInvalidFunctionBuilderBody * + duringConstraintGeneration(ConstraintSystem &cs, ConstraintLocator *locator) { + return create(cs, ErrorInPhase::ConstraintGeneration, locator); + } + +private: + static IgnoreInvalidFunctionBuilderBody * + create(ConstraintSystem &cs, ErrorInPhase phase, ConstraintLocator *locator); }; } // end namespace constraints From 04da864090b66905f91a270ceee6cabc19142926 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sat, 29 Aug 2020 21:39:10 -0700 Subject: [PATCH 498/663] [semantic-arc] Split out owned -> guaranteed phi opt into its own file. --- lib/SILOptimizer/SemanticARC/CMakeLists.txt | 3 +- .../SemanticARC/OwnedToGuaranteedPhiOpt.cpp | 257 ++++++++++++++++++ .../SemanticARC/SemanticARCOptVisitor.h | 2 + .../SemanticARC/SemanticARCOpts.cpp | 236 +--------------- 4 files changed, 265 insertions(+), 233 deletions(-) create mode 100644 lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt index f2ebe23343f96..24d12d704ff4d 100644 --- a/lib/SILOptimizer/SemanticARC/CMakeLists.txt +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(swiftSILOptimizer PRIVATE OwnershipLiveRange.cpp LoadCopyToLoadBorrowOpt.cpp BorrowScopeOpts.cpp - CopyValueOpts.cpp) + CopyValueOpts.cpp + OwnedToGuaranteedPhiOpt.cpp) diff --git a/lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp b/lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp new file mode 100644 index 0000000000000..b2740a0ce47ab --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp @@ -0,0 +1,257 @@ +//===--- OwnedToGuaranteedPhiOpt.cpp --------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Late optimization that eliminates webs of owned phi nodes. +/// +//===----------------------------------------------------------------------===// + +#include "OwnershipPhiOperand.h" +#include "SemanticARCOptVisitor.h" + +using namespace swift; +using namespace swift::semanticarc; + +static bool canEliminatePhi( + SemanticARCOptVisitor::FrozenMultiMapRange optimizableIntroducerRange, + ArrayRef incomingValueOperandList, + SmallVectorImpl &ownedValueIntroducerAccumulator) { + for (auto incomingValueOperand : incomingValueOperandList) { + SILValue incomingValue = incomingValueOperand.getValue(); + + // Before we do anything, see if we have an incoming value with trivial + // ownership. This can occur in the case where we are working with enums due + // to trivial non-payloaded cases. Skip that. + if (incomingValue.getOwnershipKind() == ValueOwnershipKind::None) { + continue; + } + + // Then see if this is an introducer that we actually saw as able to be + // optimized if we could flip this joined live range. + // + // NOTE: If this linear search is too slow, we can change the multimap to + // sort the mapped to list by pointer instead of insertion order. In such a + // case, we could then bisect. + if (llvm::find(optimizableIntroducerRange, + incomingValueOperand.getOperand()) == + optimizableIntroducerRange.end()) { + return false; + } + + // Now that we know it is an owned value that we saw before, check for + // introducers of the owned value which are the copies that we may be able + // to eliminate. Since we do not look through joined live ranges, we must + // only have a single introducer. So look for that one and if not, bail. + auto singleIntroducer = getSingleOwnedValueIntroducer(incomingValue); + if (!singleIntroducer.hasValue()) { + return false; + } + + // Then make sure that our owned value introducer is able to be converted to + // guaranteed and that we found it to have a LiveRange that we could have + // eliminated /if/ we were to get rid of this phi. + if (!singleIntroducer->isConvertableToGuaranteed()) { + return false; + } + + // Otherwise, add the introducer to our result array. + ownedValueIntroducerAccumulator.push_back(*singleIntroducer); + } + +#ifndef NDEBUG + // Other parts of the pass ensure that we only add values to the list if their + // owned value introducer is not used by multiple live ranges. That being + // said, lets assert that. + { + SmallVector uniqueCheck; + llvm::copy(ownedValueIntroducerAccumulator, + std::back_inserter(uniqueCheck)); + sortUnique(uniqueCheck); + assert( + uniqueCheck.size() == ownedValueIntroducerAccumulator.size() && + "multiple joined live range operands are from the same live range?!"); + } +#endif + + return true; +} + +static bool getIncomingJoinedLiveRangeOperands( + SILValue joinedLiveRange, + SmallVectorImpl &resultingOperands) { + if (auto *phi = dyn_cast(joinedLiveRange)) { + return phi->visitIncomingPhiOperands([&](Operand *op) { + if (auto phiOp = OwnershipPhiOperand::get(op)) { + resultingOperands.push_back(*phiOp); + return true; + } + return false; + }); + } + + if (auto *svi = dyn_cast(joinedLiveRange)) { + return llvm::all_of(svi->getAllOperands(), [&](const Operand &op) { + // skip type dependent operands. + if (op.isTypeDependent()) + return true; + + auto phiOp = OwnershipPhiOperand::get(&op); + if (!phiOp) + return false; + resultingOperands.push_back(*phiOp); + return true; + }); + } + + llvm_unreachable("Unhandled joined live range?!"); +} + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { + bool madeChange = false; + + // First freeze our multi-map so we can use it for map queries. Also, setup a + // defer of the reset so we do not forget to reset the map when we are done. + joinedOwnedIntroducerToConsumedOperands.setFrozen(); + SWIFT_DEFER { joinedOwnedIntroducerToConsumedOperands.reset(); }; + + // Now for each phi argument that we have in our multi-map... + SmallVector incomingValueOperandList; + SmallVector ownedValueIntroducers; + for (auto pair : joinedOwnedIntroducerToConsumedOperands.getRange()) { + SWIFT_DEFER { + incomingValueOperandList.clear(); + ownedValueIntroducers.clear(); + }; + + // First compute the LiveRange for ownershipPhi value. For simplicity, we + // only handle cases now where the result does not have any additional + // ownershipPhi uses. + SILValue joinedIntroducer = pair.first; + OwnershipLiveRange joinedLiveRange(joinedIntroducer); + if (bool(joinedLiveRange.hasUnknownConsumingUse())) { + continue; + } + + // Ok, we know that our phi argument /could/ be converted to guaranteed if + // our incoming values are able to be converted to guaranteed. Now for each + // incoming value, compute the incoming values ownership roots and see if + // all of the ownership roots are in our owned incoming value array. + if (!getIncomingJoinedLiveRangeOperands(joinedIntroducer, + incomingValueOperandList)) { + continue; + } + + // Grab our list of introducer values paired with this SILArgument. See if + // all of these introducer values were ones that /could/ have been + // eliminated if it was not for the given phi. If all of them are, we can + // optimize! + { + auto rawFoundOptimizableIntroducerArray = pair.second; + if (!canEliminatePhi(rawFoundOptimizableIntroducerArray, + incomingValueOperandList, ownedValueIntroducers)) { + continue; + } + } + + // Ok, at this point we know that we can eliminate this phi. First go + // through the list of incomingValueOperandList and stash the value/set the + // operand's stored value to undef. We will hook them back up later. + SmallVector originalIncomingValues; + for (auto &incomingValueOperand : incomingValueOperandList) { + originalIncomingValues.push_back(incomingValueOperand.getValue()); + incomingValueOperand.markUndef(); + } + + // Then go through all of our owned value introducers, compute their live + // ranges, and eliminate them. We know it is safe to remove them from our + // previous proofs. + // + // NOTE: If our introducer is a copy_value that is one of our + // originalIncomingValues, we need to update the originalIncomingValue array + // with that value since we are going to delete the copy_value here. This + // creates a complication since we want to binary_search on + // originalIncomingValues to detect this same condition! So, we create a + // list of updates that we apply after we no longer need to perform + // binary_search, but before we start RAUWing things. + SmallVector, 8> incomingValueUpdates; + for (auto introducer : ownedValueIntroducers) { + SILValue v = introducer.value; + OwnershipLiveRange lr(v); + + // For now, we only handle copy_value for simplicity. + // + // TODO: Add support for load [copy]. + if (introducer.kind == OwnedValueIntroducerKind::Copy) { + auto *cvi = cast(v); + // Before we convert from owned to guaranteed, we need to first see if + // cvi is one of our originalIncomingValues. If so, we need to set + // originalIncomingValues to be cvi->getOperand(). Otherwise, weirdness + // results since we are deleting one of our stashed values. + auto iter = find(originalIncomingValues, cvi); + if (iter != originalIncomingValues.end()) { + // We use an auxillary array here so we can continue to bisect on + // original incoming values. Once we are done processing here, we will + // not need that property anymore. + unsigned updateOffset = + std::distance(originalIncomingValues.begin(), iter); + incomingValueUpdates.emplace_back(cvi->getOperand(), updateOffset); + } + std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), + getCallbacks()); + continue; + } + llvm_unreachable("Unhandled optimizable introducer!"); + } + + // Now go through and update our original incoming value array now that we + // do not need it to be sorted for bisection purposes. + while (!incomingValueUpdates.empty()) { + auto pair = incomingValueUpdates.pop_back_val(); + originalIncomingValues[pair.second] = pair.first; + } + + // Then convert the phi's live range to be guaranteed. + std::move(joinedLiveRange) + .convertJoinedLiveRangePhiToGuaranteed( + getDeadEndBlocks(), lifetimeFrontier, getCallbacks()); + + // Now if our phi operand consumes/forwards its guaranteed input, insert a + // begin_borrow along the incoming value edges. We have to do this after + // converting the incoming values to be guaranteed to avoid tripping + // SILBuilder checks around simple ownership invariants (namely that def/use + // line up) when creating instructions. + assert(incomingValueOperandList.size() == originalIncomingValues.size()); + while (!incomingValueOperandList.empty()) { + auto incomingValueOperand = incomingValueOperandList.pop_back_val(); + SILValue originalValue = originalIncomingValues.pop_back_val(); + if (incomingValueOperand.isGuaranteedConsuming() && + originalValue.getOwnershipKind() != ValueOwnershipKind::None) { + auto loc = RegularLocation::getAutoGeneratedLocation(); + SILBuilderWithScope builder(incomingValueOperand.getInst()); + originalValue = builder.createBeginBorrow(loc, originalValue); + } + incomingValueOperand.getOperand()->set(originalValue); + } + + madeChange = true; + if (VerifyAfterTransform) { + F.verify(); + } + } + + return madeChange; +} diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h index 7a8be8ea7982d..038ca712fce8e 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h @@ -27,6 +27,8 @@ namespace swift { namespace semanticarc { +extern bool VerifyAfterTransform; + bool constructCacheValue( SILValue initialValue, SmallVectorImpl &wellBehavedWriteAccumulator); diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index cc57de73f7c5c..ba60b34bf9982 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -49,239 +49,11 @@ using namespace swift::semanticarc; // Implementation //===----------------------------------------------------------------------===// -static llvm::cl::opt - VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", - llvm::cl::init(false), llvm::cl::Hidden); - -static bool canEliminatePhi( - SemanticARCOptVisitor::FrozenMultiMapRange optimizableIntroducerRange, - ArrayRef incomingValueOperandList, - SmallVectorImpl &ownedValueIntroducerAccumulator) { - for (auto incomingValueOperand : incomingValueOperandList) { - SILValue incomingValue = incomingValueOperand.getValue(); - - // Before we do anything, see if we have an incoming value with trivial - // ownership. This can occur in the case where we are working with enums due - // to trivial non-payloaded cases. Skip that. - if (incomingValue.getOwnershipKind() == ValueOwnershipKind::None) { - continue; - } - - // Then see if this is an introducer that we actually saw as able to be - // optimized if we could flip this joined live range. - // - // NOTE: If this linear search is too slow, we can change the multimap to - // sort the mapped to list by pointer instead of insertion order. In such a - // case, we could then bisect. - if (llvm::find(optimizableIntroducerRange, - incomingValueOperand.getOperand()) == - optimizableIntroducerRange.end()) { - return false; - } - - // Now that we know it is an owned value that we saw before, check for - // introducers of the owned value which are the copies that we may be able - // to eliminate. Since we do not look through joined live ranges, we must - // only have a single introducer. So look for that one and if not, bail. - auto singleIntroducer = getSingleOwnedValueIntroducer(incomingValue); - if (!singleIntroducer.hasValue()) { - return false; - } - - // Then make sure that our owned value introducer is able to be converted to - // guaranteed and that we found it to have a LiveRange that we could have - // eliminated /if/ we were to get rid of this phi. - if (!singleIntroducer->isConvertableToGuaranteed()) { - return false; - } - - // Otherwise, add the introducer to our result array. - ownedValueIntroducerAccumulator.push_back(*singleIntroducer); - } - -#ifndef NDEBUG - // Other parts of the pass ensure that we only add values to the list if their - // owned value introducer is not used by multiple live ranges. That being - // said, lets assert that. - { - SmallVector uniqueCheck; - llvm::copy(ownedValueIntroducerAccumulator, - std::back_inserter(uniqueCheck)); - sortUnique(uniqueCheck); - assert( - uniqueCheck.size() == ownedValueIntroducerAccumulator.size() && - "multiple joined live range operands are from the same live range?!"); - } -#endif +bool swift::semanticarc::VerifyAfterTransform; - return true; -} - -static bool getIncomingJoinedLiveRangeOperands( - SILValue joinedLiveRange, - SmallVectorImpl &resultingOperands) { - if (auto *phi = dyn_cast(joinedLiveRange)) { - return phi->visitIncomingPhiOperands([&](Operand *op) { - if (auto phiOp = OwnershipPhiOperand::get(op)) { - resultingOperands.push_back(*phiOp); - return true; - } - return false; - }); - } - - if (auto *svi = dyn_cast(joinedLiveRange)) { - return llvm::all_of(svi->getAllOperands(), [&](const Operand &op) { - // skip type dependent operands. - if (op.isTypeDependent()) - return true; - - auto phiOp = OwnershipPhiOperand::get(&op); - if (!phiOp) - return false; - resultingOperands.push_back(*phiOp); - return true; - }); - } - - llvm_unreachable("Unhandled joined live range?!"); -} - -bool SemanticARCOptVisitor::performPostPeepholeOwnedArgElimination() { - bool madeChange = false; - - // First freeze our multi-map so we can use it for map queries. Also, setup a - // defer of the reset so we do not forget to reset the map when we are done. - joinedOwnedIntroducerToConsumedOperands.setFrozen(); - SWIFT_DEFER { joinedOwnedIntroducerToConsumedOperands.reset(); }; - - // Now for each phi argument that we have in our multi-map... - SmallVector incomingValueOperandList; - SmallVector ownedValueIntroducers; - for (auto pair : joinedOwnedIntroducerToConsumedOperands.getRange()) { - SWIFT_DEFER { - incomingValueOperandList.clear(); - ownedValueIntroducers.clear(); - }; - - // First compute the LiveRange for ownershipPhi value. For simplicity, we - // only handle cases now where the result does not have any additional - // ownershipPhi uses. - SILValue joinedIntroducer = pair.first; - OwnershipLiveRange joinedLiveRange(joinedIntroducer); - if (bool(joinedLiveRange.hasUnknownConsumingUse())) { - continue; - } - - // Ok, we know that our phi argument /could/ be converted to guaranteed if - // our incoming values are able to be converted to guaranteed. Now for each - // incoming value, compute the incoming values ownership roots and see if - // all of the ownership roots are in our owned incoming value array. - if (!getIncomingJoinedLiveRangeOperands(joinedIntroducer, - incomingValueOperandList)) { - continue; - } - - // Grab our list of introducer values paired with this SILArgument. See if - // all of these introducer values were ones that /could/ have been - // eliminated if it was not for the given phi. If all of them are, we can - // optimize! - { - auto rawFoundOptimizableIntroducerArray = pair.second; - if (!canEliminatePhi(rawFoundOptimizableIntroducerArray, - incomingValueOperandList, ownedValueIntroducers)) { - continue; - } - } - - // Ok, at this point we know that we can eliminate this phi. First go - // through the list of incomingValueOperandList and stash the value/set the - // operand's stored value to undef. We will hook them back up later. - SmallVector originalIncomingValues; - for (auto &incomingValueOperand : incomingValueOperandList) { - originalIncomingValues.push_back(incomingValueOperand.getValue()); - incomingValueOperand.markUndef(); - } - - // Then go through all of our owned value introducers, compute their live - // ranges, and eliminate them. We know it is safe to remove them from our - // previous proofs. - // - // NOTE: If our introducer is a copy_value that is one of our - // originalIncomingValues, we need to update the originalIncomingValue array - // with that value since we are going to delete the copy_value here. This - // creates a complication since we want to binary_search on - // originalIncomingValues to detect this same condition! So, we create a - // list of updates that we apply after we no longer need to perform - // binary_search, but before we start RAUWing things. - SmallVector, 8> incomingValueUpdates; - for (auto introducer : ownedValueIntroducers) { - SILValue v = introducer.value; - OwnershipLiveRange lr(v); - - // For now, we only handle copy_value for simplicity. - // - // TODO: Add support for load [copy]. - if (introducer.kind == OwnedValueIntroducerKind::Copy) { - auto *cvi = cast(v); - // Before we convert from owned to guaranteed, we need to first see if - // cvi is one of our originalIncomingValues. If so, we need to set - // originalIncomingValues to be cvi->getOperand(). Otherwise, weirdness - // results since we are deleting one of our stashed values. - auto iter = find(originalIncomingValues, cvi); - if (iter != originalIncomingValues.end()) { - // We use an auxillary array here so we can continue to bisect on - // original incoming values. Once we are done processing here, we will - // not need that property anymore. - unsigned updateOffset = - std::distance(originalIncomingValues.begin(), iter); - incomingValueUpdates.emplace_back(cvi->getOperand(), updateOffset); - } - std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), - getCallbacks()); - continue; - } - llvm_unreachable("Unhandled optimizable introducer!"); - } - - // Now go through and update our original incoming value array now that we - // do not need it to be sorted for bisection purposes. - while (!incomingValueUpdates.empty()) { - auto pair = incomingValueUpdates.pop_back_val(); - originalIncomingValues[pair.second] = pair.first; - } - - // Then convert the phi's live range to be guaranteed. - std::move(joinedLiveRange) - .convertJoinedLiveRangePhiToGuaranteed( - getDeadEndBlocks(), lifetimeFrontier, getCallbacks()); - - // Now if our phi operand consumes/forwards its guaranteed input, insert a - // begin_borrow along the incoming value edges. We have to do this after - // converting the incoming values to be guaranteed to avoid tripping - // SILBuilder checks around simple ownership invariants (namely that def/use - // line up) when creating instructions. - assert(incomingValueOperandList.size() == originalIncomingValues.size()); - while (!incomingValueOperandList.empty()) { - auto incomingValueOperand = incomingValueOperandList.pop_back_val(); - SILValue originalValue = originalIncomingValues.pop_back_val(); - if (incomingValueOperand.isGuaranteedConsuming() && - originalValue.getOwnershipKind() != ValueOwnershipKind::None) { - auto loc = RegularLocation::getAutoGeneratedLocation(); - SILBuilderWithScope builder(incomingValueOperand.getInst()); - originalValue = builder.createBeginBorrow(loc, originalValue); - } - incomingValueOperand.getOperand()->set(originalValue); - } - - madeChange = true; - if (VerifyAfterTransform) { - F.verify(); - } - } - - return madeChange; -} +static llvm::cl::opt VerifyAfterTransformOption( + "sil-semantic-arc-opts-verify-after-transform", llvm::cl::Hidden, + llvm::cl::location(VerifyAfterTransform), llvm::cl::init(false)); bool SemanticARCOptVisitor::optimize() { bool madeChange = false; From dd726a00157f0a356ef2190af790d0c8630b7b7c Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 1 Sep 2020 12:54:01 -0700 Subject: [PATCH 499/663] [NFC] Avoid repeatedly instantiating std::function --- include/swift/AST/PrintOptions.h | 5 ++- .../swift/SILOptimizer/Utils/InstOptUtils.h | 32 +++++++++---------- lib/AST/ASTPrinter.cpp | 5 +++ lib/SILOptimizer/Utils/InstOptUtils.cpp | 21 ++++++++++++ 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index abfebaf3ffb48..2b99e4ac1e66b 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -380,10 +380,13 @@ struct PrintOptions { /// has no associated doc-comment by itself. bool CascadeDocComment = false; + static const std::function + defaultPrintExtensionContentAsMembers; + /// Whether to print the content of an extension decl inside the type decl where it /// extends from. std::function printExtensionContentAsMembers = - [] (const ExtensionDecl *) { return false; }; + PrintOptions::defaultPrintExtensionContentAsMembers; /// How to print the keyword argument and parameter name in functions. ArgAndParamPrintingMode ArgAndParamPrinting = diff --git a/include/swift/SILOptimizer/Utils/InstOptUtils.h b/include/swift/SILOptimizer/Utils/InstOptUtils.h index 522abb0f5a68c..86c1ab802541f 100644 --- a/include/swift/SILOptimizer/Utils/InstOptUtils.h +++ b/include/swift/SILOptimizer/Utils/InstOptUtils.h @@ -308,21 +308,22 @@ bool tryCheckedCastBrJumpThreading( /// A structure containing callbacks that are called when an instruction is /// removed or added. struct InstModCallbacks { - std::function deleteInst = [](SILInstruction *inst) { - inst->eraseFromParent(); - }; - std::function createdNewInst = [](SILInstruction *) { - }; - std::function replaceValueUsesWith = - [](SILValue oldValue, SILValue newValue) { - oldValue->replaceAllUsesWith(newValue); - }; + static const std::function defaultDeleteInst; + static const std::function defaultCreatedNewInst; + static const std::function defaultReplaceValueUsesWith; + static const std::function + defaultEraseAndRAUWSingleValueInst; + + std::function deleteInst = + InstModCallbacks::defaultDeleteInst; + std::function createdNewInst = + InstModCallbacks::defaultCreatedNewInst; + std::function + replaceValueUsesWith = + InstModCallbacks::defaultReplaceValueUsesWith; std::function eraseAndRAUWSingleValueInst = - [](SingleValueInstruction *i, SILValue newValue) { - i->replaceAllUsesWith(newValue); - i->eraseFromParent(); - }; + InstModCallbacks::defaultEraseAndRAUWSingleValueInst; InstModCallbacks(decltype(deleteInst) deleteInst, decltype(createdNewInst) createdNewInst, @@ -330,10 +331,7 @@ struct InstModCallbacks { : deleteInst(deleteInst), createdNewInst(createdNewInst), replaceValueUsesWith(replaceValueUsesWith), eraseAndRAUWSingleValueInst( - [](SingleValueInstruction *i, SILValue newValue) { - i->replaceAllUsesWith(newValue); - i->eraseFromParent(); - }) {} + InstModCallbacks::defaultEraseAndRAUWSingleValueInst) {} InstModCallbacks( decltype(deleteInst) deleteInst, decltype(createdNewInst) createdNewInst, diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index eca53f2a0c0e9..ff3e609f84ca9 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -58,6 +58,11 @@ using namespace swift; +// Defined here to avoid repeatedly paying the price of template instantiation. +const std::function + PrintOptions::defaultPrintExtensionContentAsMembers + = [] (const ExtensionDecl *) { return false; }; + void PrintOptions::setBaseType(Type T) { if (T->is()) return; diff --git a/lib/SILOptimizer/Utils/InstOptUtils.cpp b/lib/SILOptimizer/Utils/InstOptUtils.cpp index 312c15d6e6984..19ce86358904c 100644 --- a/lib/SILOptimizer/Utils/InstOptUtils.cpp +++ b/lib/SILOptimizer/Utils/InstOptUtils.cpp @@ -48,6 +48,27 @@ static llvm::cl::opt KeepWillThrowCall( llvm::cl::desc( "Keep calls to swift_willThrow, even if the throw is optimized away")); +// Defined here to avoid repeatedly paying the price of template instantiation. +const std::function + InstModCallbacks::defaultDeleteInst + = [](SILInstruction *inst) { + inst->eraseFromParent(); + }; +const std::function + InstModCallbacks::defaultCreatedNewInst + = [](SILInstruction *) {}; +const std::function + InstModCallbacks::defaultReplaceValueUsesWith + = [](SILValue oldValue, SILValue newValue) { + oldValue->replaceAllUsesWith(newValue); + }; +const std::function + InstModCallbacks::defaultEraseAndRAUWSingleValueInst + = [](SingleValueInstruction *i, SILValue newValue) { + i->replaceAllUsesWith(newValue); + i->eraseFromParent(); + }; + /// Creates an increment on \p Ptr before insertion point \p InsertPt that /// creates a strong_retain if \p Ptr has reference semantics itself or a /// retain_value if \p Ptr is a non-trivial value without reference-semantics. From ae4fbb67165a728a7181e78bd32ad6ed2b94121b Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 1 Sep 2020 13:01:10 -0700 Subject: [PATCH 500/663] [AST] Generalize and rename ClassDecl::getEmittedMembers() Generalize `ClassDecl::getEmittedMembers()` to operate on an `IterableDeclContext`, so that it can be for other nominal types, extensions, etc. Rename to `getSemanticMembers()` to indicate that these are all of the members that are semantically part of that context. Clean up the implementation slightly so it only forces type checking for the conformances within that particular context (using `getLocalConformances()`) and doesn't need to list out each of the protocols it cares about. --- include/swift/AST/Decl.h | 4 -- include/swift/AST/DeclContext.h | 5 ++ include/swift/AST/TypeCheckRequests.h | 4 +- include/swift/AST/TypeCheckerTypeIDZone.def | 4 +- include/swift/SIL/SILVTableVisitor.h | 2 +- lib/AST/Decl.cpp | 7 -- lib/AST/DeclContext.cpp | 8 +++ lib/SILGen/SILGenType.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 70 ++++++++----------- lib/Sema/TypeCheckDeclPrimary.cpp | 2 +- .../single-file-private/AnyObject.swift | 1 - .../Verifier/single-file/AnyObject.swift | 1 - 12 files changed, 51 insertions(+), 59 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 5842456999735..dc089f2c9a4d0 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4074,10 +4074,6 @@ class ClassDecl final : public NominalTypeDecl { /// Record the presence of an @objc method with the given selector. void recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector); - /// Get all the members of this class, synthesizing any implicit members - /// that appear in the vtable if needed. - ArrayRef getEmittedMembers() const; - // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == DeclKind::Class; diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 36e1f07a2db56..e9984fbcf7efd 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -783,6 +783,11 @@ class IterableDeclContext { /// Retrieve the set of members in this context. DeclRange getMembers() const; + /// Get all the members that are semantically within this context, + /// including any implicitly-synthesized members. + /// The resulting list of members will be stable across translation units. + ArrayRef getSemanticMembers() const; + /// Retrieve the set of members in this context without loading any from the /// associated lazy loader; this should only be used as part of implementing /// abstractions on top of member loading, such as a name lookup table. diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index c73b37dd18e2b..d893b5ce3c41b 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1082,7 +1082,7 @@ class SynthesizeAccessorRequest : class EmittedMembersRequest : public SimpleRequest(ClassDecl *), + ArrayRef(IterableDeclContext *), RequestFlags::Cached> { public: using SimpleRequest::SimpleRequest; @@ -1092,7 +1092,7 @@ class EmittedMembersRequest : // Evaluation. ArrayRef - evaluate(Evaluator &evaluator, ClassDecl *classDecl) const; + evaluate(Evaluator &evaluator, IterableDeclContext *idc) const; public: bool isCached() const { return true; } diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index fdc161406d127..1806d226265c0 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -65,8 +65,8 @@ SWIFT_REQUEST(TypeChecker, TypeEraserHasViableInitRequest, SWIFT_REQUEST(TypeChecker, DynamicallyReplacedDeclRequest, ValueDecl *(ValueDecl *), Cached, NoLocationInfo) -SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, ArrayRef(ClassDecl *), - Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, + ArrayRef(IterableDeclContext *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, evaluator::SideEffect (EnumDecl *, TypeResolutionStage), SeparatelyCached, NoLocationInfo) diff --git a/include/swift/SIL/SILVTableVisitor.h b/include/swift/SIL/SILVTableVisitor.h index de8419b238601..2aeb6755cdecf 100644 --- a/include/swift/SIL/SILVTableVisitor.h +++ b/include/swift/SIL/SILVTableVisitor.h @@ -148,7 +148,7 @@ template class SILVTableVisitor { if (!theClass->hasKnownSwiftImplementation()) return; - for (auto member : theClass->getEmittedMembers()) + for (auto member : theClass->getSemanticMembers()) maybeAddMember(member); } }; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index f1f17cbf3c042..ea43c3cc48eb8 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4181,13 +4181,6 @@ DestructorDecl *ClassDecl::getDestructor() const { nullptr); } -ArrayRef ClassDecl::getEmittedMembers() const { - ASTContext &ctx = getASTContext(); - return evaluateOrDefault(ctx.evaluator, - EmittedMembersRequest{const_cast(this)}, - ArrayRef()); -} - /// Synthesizer callback for an empty implicit function body. static std::pair synthesizeEmptyFunctionBody(AbstractFunctionDecl *afd, void *context) { diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 5f7733df66c2b..8fac7e3d86f61 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -793,6 +793,14 @@ DeclRange IterableDeclContext::getMembers() const { return getCurrentMembersWithoutLoading(); } +ArrayRef IterableDeclContext::getSemanticMembers() const { + ASTContext &ctx = getASTContext(); + return evaluateOrDefault( + ctx.evaluator, + EmittedMembersRequest{const_cast(this)}, + ArrayRef()); +} + /// Add a member to this context. void IterableDeclContext::addMember(Decl *member, Decl *Hint) { // Add the member to the list of declarations without notification. diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 83f2de20c78f3..d30a74087fc3e 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -1038,7 +1038,7 @@ class SILGenType : public TypeMemberVisitor { // Build a vtable if this is a class. if (auto theClass = dyn_cast(theType)) { - for (Decl *member : theClass->getEmittedMembers()) + for (Decl *member : theClass->getSemanticMembers()) visit(member); SILGenVTable genVTable(SGM, theClass); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 93c9effd91e74..d5f11461830ea 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2507,59 +2507,51 @@ struct SortedFuncList { ArrayRef EmittedMembersRequest::evaluate(Evaluator &evaluator, - ClassDecl *CD) const { - auto &Context = CD->getASTContext(); + IterableDeclContext *idc) const { + auto dc = cast(idc->getDecl()); + auto &Context = dc->getASTContext(); SmallVector result; - if (!CD->getParentSourceFile()) { - auto members = CD->getMembers(); + if (!dc->getParentSourceFile()) { + auto members = idc->getMembers(); result.append(members.begin(), members.end()); return Context.AllocateCopy(result); } - // We need to add implicit initializers because they - // affect vtable layout. - TypeChecker::addImplicitConstructors(CD); + auto nominal = dyn_cast(idc); - auto forceConformance = [&](ProtocolDecl *protocol) { - auto ref = CD->getParentModule()->lookupConformance( - CD->getDeclaredInterfaceType(), protocol); - if (ref.isInvalid()) { - return; - } + if (nominal) { + // We need to add implicit initializers because they + // affect vtable layout. + TypeChecker::addImplicitConstructors(nominal); + } - auto conformance = ref.getConcrete(); - if (conformance->getDeclContext() == CD && - conformance->getState() == ProtocolConformanceState::Incomplete) { + // Force any derivable conformances in this context. This ensures that any + // synthesized members will approach in the member list. + for (auto conformance : idc->getLocalConformances()) { + if (conformance->getState() == ProtocolConformanceState::Incomplete && + conformance->getProtocol()->getKnownDerivableProtocolKind()) TypeChecker::checkConformance(conformance->getRootNormalConformance()); - } - }; + } - // If the class is Encodable, Decodable or Hashable, force those - // conformances to ensure that the synthesized members appear in the vtable. - // - // FIXME: Generalize this to other protocols for which - // we can derive conformances. - forceConformance(Context.getProtocol(KnownProtocolKind::Decodable)); - forceConformance(Context.getProtocol(KnownProtocolKind::Encodable)); - forceConformance(Context.getProtocol(KnownProtocolKind::Hashable)); - forceConformance(Context.getProtocol(KnownProtocolKind::Differentiable)); - - // If the class conforms to Encodable or Decodable, even via an extension, + // If the type conforms to Encodable or Decodable, even via an extension, // the CodingKeys enum is synthesized as a member of the type itself. // Force it into existence. - (void) evaluateOrDefault(Context.evaluator, - ResolveImplicitMemberRequest{CD, - ImplicitMemberAction::ResolveCodingKeys}, - {}); + if (nominal) { + (void) evaluateOrDefault(Context.evaluator, + ResolveImplicitMemberRequest{nominal, + ImplicitMemberAction::ResolveCodingKeys}, + {}); + } - // If the class has a @main attribute, we need to force synthesis of the + // If the decl has a @main attribute, we need to force synthesis of the // $main function. - (void) evaluateOrDefault(Context.evaluator, - SynthesizeMainFunctionRequest{CD}, - nullptr); + (void) evaluateOrDefault( + Context.evaluator, + SynthesizeMainFunctionRequest{const_cast(idc->getDecl())}, + nullptr); - for (auto *member : CD->getMembers()) { + for (auto *member : idc->getMembers()) { if (auto *var = dyn_cast(member)) { // The projected storage wrapper ($foo) might have dynamically-dispatched // accessors, so force them to be synthesized. @@ -2570,7 +2562,7 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, SortedFuncList synthesizedMembers; - for (auto *member : CD->getMembers()) { + for (auto *member : idc->getMembers()) { if (auto *afd = dyn_cast(member)) { // Add synthesized members to a side table and sort them by their mangled // name, since they could have been added to the class in any order. diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 2e9a3c01bf1ab..a342b4ff067b2 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2017,7 +2017,7 @@ class DeclChecker : public DeclVisitor { TypeChecker::checkDeclAttributes(CD); - for (Decl *Member : CD->getEmittedMembers()) + for (Decl *Member : CD->getSemanticMembers()) visit(Member); TypeChecker::checkPatternBindingCaptures(CD); diff --git a/test/Incremental/Verifier/single-file-private/AnyObject.swift b/test/Incremental/Verifier/single-file-private/AnyObject.swift index 2e80b90832cab..ff93b85405252 100644 --- a/test/Incremental/Verifier/single-file-private/AnyObject.swift +++ b/test/Incremental/Verifier/single-file-private/AnyObject.swift @@ -25,7 +25,6 @@ import Foundation // expected-private-conformance {{Swift.CVarArg}} // expected-private-conformance {{Swift.CustomStringConvertible}} // expected-private-member {{Swift._ExpressibleByBuiltinIntegerLiteral.init}} -// expected-private-superclass {{main.LookupFactory}} @objc private class LookupFactory: NSObject { // expected-provides {{AssignmentPrecedence}} // expected-provides {{IntegerLiteralType}} diff --git a/test/Incremental/Verifier/single-file/AnyObject.swift b/test/Incremental/Verifier/single-file/AnyObject.swift index 63a5e55f68007..0130674af6552 100644 --- a/test/Incremental/Verifier/single-file/AnyObject.swift +++ b/test/Incremental/Verifier/single-file/AnyObject.swift @@ -25,7 +25,6 @@ import Foundation // expected-private-conformance {{Swift.CVarArg}} // expected-private-conformance {{Swift.CustomStringConvertible}} // expected-cascading-member {{Swift._ExpressibleByBuiltinIntegerLiteral.init}} -// expected-cascading-superclass {{main.LookupFactory}} @objc private class LookupFactory: NSObject { // expected-provides {{AssignmentPrecedence}} // expected-provides {{IntegerLiteralType}} From 650a8b25da8b8c61f6380d155f40a92e9f4ee6f5 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 1 Sep 2020 13:21:59 -0700 Subject: [PATCH 501/663] [AST] Rename EmittedMembersRequest -> SemanticMembersRequest. --- include/swift/AST/Decl.h | 2 +- include/swift/AST/TypeCheckRequests.h | 4 ++-- include/swift/AST/TypeCheckerTypeIDZone.def | 2 +- lib/AST/DeclContext.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index dc089f2c9a4d0..c9448731e3a85 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3886,7 +3886,7 @@ class ClassDecl final : public NominalTypeDecl { friend class SuperclassDeclRequest; friend class SuperclassTypeRequest; - friend class EmittedMembersRequest; + friend class SemanticMembersRequest; friend class HasMissingDesignatedInitializersRequest; friend class InheritsSuperclassInitializersRequest; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index d893b5ce3c41b..8e03a00338a45 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1080,8 +1080,8 @@ class SynthesizeAccessorRequest : void cacheResult(AccessorDecl *value) const; }; -class EmittedMembersRequest : - public SimpleRequest(IterableDeclContext *), RequestFlags::Cached> { public: diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 1806d226265c0..bcc4148926da7 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -65,7 +65,7 @@ SWIFT_REQUEST(TypeChecker, TypeEraserHasViableInitRequest, SWIFT_REQUEST(TypeChecker, DynamicallyReplacedDeclRequest, ValueDecl *(ValueDecl *), Cached, NoLocationInfo) -SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, +SWIFT_REQUEST(TypeChecker, SemanticMembersRequest, ArrayRef(IterableDeclContext *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, evaluator::SideEffect (EnumDecl *, TypeResolutionStage), diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 8fac7e3d86f61..c54e9b2f53f6e 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -797,7 +797,7 @@ ArrayRef IterableDeclContext::getSemanticMembers() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, - EmittedMembersRequest{const_cast(this)}, + SemanticMembersRequest{const_cast(this)}, ArrayRef()); } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d5f11461830ea..02dbecde67319 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2506,7 +2506,7 @@ struct SortedFuncList { } // end namespace ArrayRef -EmittedMembersRequest::evaluate(Evaluator &evaluator, +SemanticMembersRequest::evaluate(Evaluator &evaluator, IterableDeclContext *idc) const { auto dc = cast(idc->getDecl()); auto &Context = dc->getASTContext(); From c17bdaf71557ec59c1141dc0ca9e1fde0fb3803e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 1 Sep 2020 13:57:03 -0700 Subject: [PATCH 502/663] [AST] Adjust Diagnostic transaction to only track pending errors --- include/swift/AST/DiagnosticEngine.h | 17 +++++++++++++---- lib/Sema/BuilderTransform.cpp | 4 ++-- lib/Sema/CSFix.cpp | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 6d4fe61bbd4e2..338f146922b5e 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -1058,10 +1058,19 @@ namespace swift { } } - bool hasDiagnostics() const { - return std::distance(Engine.TentativeDiagnostics.begin() + - PrevDiagnostics, - Engine.TentativeDiagnostics.end()) > 0; + bool hasErrors() const { + ArrayRef diagnostics(Engine.TentativeDiagnostics.begin() + + PrevDiagnostics, + Engine.TentativeDiagnostics.end()); + + for (auto &diagnostic : diagnostics) { + auto behavior = Engine.state.determineBehavior(diagnostic.getID()); + if (behavior == DiagnosticState::Behavior::Fatal || + behavior == DiagnosticState::Behavior::Error) + return true; + } + + return false; } /// Abort and close this transaction and erase all diagnostics diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 7c35c1250db80..c1a81fcf8a676 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1719,7 +1719,7 @@ ConstraintSystem::matchFunctionBuilder( if (!applied) return getTypeMatchFailure(locator); - if (transaction.hasDiagnostics()) { + if (transaction.hasErrors()) { if (recordFix( IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration( *this, getConstraintLocator(fn.getBody())))) @@ -1814,7 +1814,7 @@ class PreCheckFunctionBuilderApplication : public ASTWalker { HasError |= ConstraintSystem::preCheckExpression( E, DC, /*replaceInvalidRefsWithErrors=*/false); - HasError |= transaction.hasDiagnostics(); + HasError |= transaction.hasErrors(); if (SuppressDiagnostics) transaction.abort(); diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 8dd90f0f9ca8d..57234af2edda2 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1588,7 +1588,7 @@ bool IgnoreInvalidFunctionBuilderBody::diagnose(const Solution &solution, } bool diagnosed() const { - return Transaction.hasDiagnostics(); + return Transaction.hasErrors(); } }; From ccca4fd25de1c0cbd774e10150dbf20c1222fe1e Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 1 Sep 2020 13:58:30 -0700 Subject: [PATCH 503/663] [AST] Add IterableDeclContext::getParsedMembers(). Provide an accessor for retrieving the parsed members, generalizing `ParseMembersRequest` so it can provide the parsed members for deserialized/synthesized declarations as well. This is the counterpart to the recently-generalized `getSemanticMembers()`; together, these should suffice for most (all?) clients of `getMembers()`. --- include/swift/AST/DeclContext.h | 5 +++++ lib/AST/DeclContext.cpp | 14 ++++++++++---- lib/Parse/ParseRequests.cpp | 22 ++++++++++++++++++---- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index e9984fbcf7efd..c41eaa46a8b40 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -783,6 +783,11 @@ class IterableDeclContext { /// Retrieve the set of members in this context. DeclRange getMembers() const; + /// Get the members that were syntactically present in the source code, + /// and will not contain any members that are implicitly synthesized by + /// the implementation. + ArrayRef getParsedMembers() const; + /// Get all the members that are semantically within this context, /// including any implicitly-synthesized members. /// The resulting list of members will be stable across translation units. diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index c54e9b2f53f6e..f1cc0b4722107 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -793,6 +793,15 @@ DeclRange IterableDeclContext::getMembers() const { return getCurrentMembersWithoutLoading(); } +ArrayRef IterableDeclContext::getParsedMembers() const { + ASTContext &ctx = getASTContext(); + auto mutableThis = const_cast(this); + return evaluateOrDefault( + ctx.evaluator, ParseMembersRequest{mutableThis}, + FingerprintAndMembers()) + .members; +} + ArrayRef IterableDeclContext::getSemanticMembers() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( @@ -899,10 +908,7 @@ void IterableDeclContext::loadAllMembers() const { // members to this context, this call is important for recording the // dependency edge. auto mutableThis = const_cast(this); - auto members = - evaluateOrDefault(ctx.evaluator, ParseMembersRequest{mutableThis}, - FingerprintAndMembers()) - .members; + auto members = getParsedMembers(); // If we haven't already done so, add these members to this context. if (!AddedParsedMembers) { diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index e0399897c1baa..99a4b3a3c5d1f 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -49,15 +49,29 @@ void swift::simple_display(llvm::raw_ostream &out, FingerprintAndMembers ParseMembersRequest::evaluate(Evaluator &evaluator, IterableDeclContext *idc) const { - SourceFile &sf = *idc->getAsGenericContext()->getParentSourceFile(); - unsigned bufferID = *sf.getBufferID(); + SourceFile *sf = idc->getAsGenericContext()->getParentSourceFile(); + ASTContext &ctx = idc->getDecl()->getASTContext(); + if (!sf) { + // If there is no parent source file, this is a deserialized or synthesized + // declaration context, in which case `getMembers()` has all of the members. + // Filter out the implicitly-generated ones. + SmallVector members; + for (auto decl : idc->getMembers()) { + if (!decl->isImplicit()) { + members.push_back(decl); + } + } + + return FingerprintAndMembers{None, ctx.AllocateCopy(members)}; + } + + unsigned bufferID = *sf->getBufferID(); // Lexer diaganostics have been emitted during skipping, so we disable lexer's // diagnostic engine here. - Parser parser(bufferID, sf, /*No Lexer Diags*/nullptr, nullptr, nullptr); + Parser parser(bufferID, *sf, /*No Lexer Diags*/nullptr, nullptr, nullptr); // Disable libSyntax creation in the delayed parsing. parser.SyntaxContext->disable(); - ASTContext &ctx = idc->getDecl()->getASTContext(); auto declsAndHash = parser.parseDeclListDelayed(idc); FingerprintAndMembers fingerprintAndMembers = {declsAndHash.second, declsAndHash.first}; From c403b140e17021cb6db9391d5ede70bc03b8c6d1 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 27 Aug 2020 23:00:51 -0700 Subject: [PATCH 504/663] ClangImporter: refactor ClangImporterOptions to be ASTContext-owned. NFC We need ClangImporterOptions to be persistent for several scenarios: (1) when creating a sub-ASTContext to build Swift modules from interfaces; and (2) when creating a new Clang instance to invoke Clang dependencies scanner. This change is NFC. --- include/swift/AST/ASTContext.h | 8 +- include/swift/Basic/LangOptions.h | 109 ++++++++++++++ include/swift/ClangImporter/ClangImporter.h | 8 +- .../ClangImporter/ClangImporterOptions.h | 133 ------------------ include/swift/Frontend/Frontend.h | 1 - lib/AST/ASTContext.cpp | 9 +- lib/ClangImporter/ClangImporter.cpp | 52 ++++--- .../ClangModuleDependencyScanner.cpp | 27 +--- lib/ClangImporter/ImportName.cpp | 1 - lib/ClangImporter/ImporterImpl.h | 8 +- lib/Frontend/Frontend.cpp | 8 +- lib/IDE/CompletionInstance.cpp | 4 +- lib/Parse/Parser.cpp | 5 +- tools/driver/modulewrap_main.cpp | 8 +- .../swift-api-digester/swift-api-digester.cpp | 3 +- unittests/AST/TestContext.cpp | 4 +- unittests/AST/TestContext.h | 1 + .../ClangImporter/ClangImporterTests.cpp | 6 +- unittests/FrontendTool/ModuleLoadingTests.cpp | 4 +- 19 files changed, 184 insertions(+), 215 deletions(-) delete mode 100644 include/swift/ClangImporter/ClangImporterOptions.h diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 7697baf4d1d01..fd020c6eb703b 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -214,7 +214,9 @@ class ASTContext final { void operator=(const ASTContext&) = delete; ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, - SearchPathOptions &SearchPathOpts, SourceManager &SourceMgr, + SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, + SourceManager &SourceMgr, DiagnosticEngine &Diags); public: @@ -228,6 +230,7 @@ class ASTContext final { static ASTContext *get(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags); ~ASTContext(); @@ -246,6 +249,9 @@ class ASTContext final { /// The search path options used by this AST context. SearchPathOptions &SearchPathOpts; + /// The clang importer options used by this AST context. + ClangImporterOptions &ClangImporterOpts; + /// The source manager object. SourceManager &SourceMgr; diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 6531ecdf0e5c8..557714ae6bf0b 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -577,6 +577,115 @@ namespace swift { /// parameters of closures. bool EnableOneWayClosureParameters = false; }; + + /// Options for controlling the behavior of the Clang importer. + class ClangImporterOptions final { + public: + /// The module cache path which the Clang importer should use. + std::string ModuleCachePath; + + /// Extra arguments which should be passed to the Clang importer. + std::vector ExtraArgs; + + /// A directory for overriding Clang's resource directory. + std::string OverrideResourceDir; + + /// The target CPU to compile for. + /// + /// Equivalent to Clang's -mcpu=. + std::string TargetCPU; + + /// The path to which we should store indexing data, if any. + std::string IndexStorePath; + + /// The bridging header or PCH that will be imported. + std::string BridgingHeader; + + /// When automatically generating a precompiled header from the bridging + /// header, place it in this directory. + std::string PrecompiledHeaderOutputDir; + + /// The optimizaton setting. This doesn't typically matter for + /// import, but it can affect Clang's IR generation of static functions. + std::string Optimization; + + /// Disable validating the persistent PCH. + bool PCHDisableValidation = false; + + /// \see Mode + enum class Modes : uint8_t { + /// Set up Clang for importing modules into Swift and generating IR from + /// Swift code. + Normal, + /// Set up Clang for backend compilation only. + EmbedBitcode, + /// Set up Clang to emit a precompiled module from a C/Objective-C module + /// map or dump debugging info about a precompiled module. + PrecompiledModule + }; + + /// Controls how Clang is initially set up. + Modes Mode = Modes::Normal; + + /// When set, preserves more information during import. + /// + /// Also \em disables some information that is only needed for object file + /// generation. + bool DetailedPreprocessingRecord = false; + + /// If true, Clang diagnostics will be dumped to stderr using Clang's + /// diagnostic printer as well as being passed to Swift's diagnostic engine. + bool DumpClangDiagnostics = false; + + /// If true, forward declarations will be imported using unavailable types + /// instead of dropped altogether when possible. + bool ImportForwardDeclarations = false; + + /// Whether to use the import as member inference system + /// + /// When importing a global, try to infer whether we can import it as a + /// member of some type instead. This includes inits, computed properties, + /// and methods. + bool InferImportAsMember = false; + + /// If true ignore the swift bridged attribute. + bool DisableSwiftBridgeAttr = false; + + /// When set, don't look for or load overlays. + bool DisableOverlayModules = false; + + /// When set, don't enforce warnings with -Werror. + bool DebuggerSupport = false; + + /// When set, ClangImporter is disabled, and all requests go to the + /// DWARFImporter delegate. + bool DisableSourceImport = false; + + /// When set, use ExtraArgs alone to configure clang instance because ExtraArgs + /// contains the full option set. + bool ExtraArgsOnly = false; + + /// Return a hash code of any components from these options that should + /// contribute to a Swift Bridging PCH hash. + llvm::hash_code getPCHHashComponents() const { + using llvm::hash_combine; + using llvm::hash_combine_range; + + return hash_combine(ModuleCachePath, + hash_combine_range(ExtraArgs.begin(), ExtraArgs.end()), + OverrideResourceDir, + TargetCPU, + BridgingHeader, + PrecompiledHeaderOutputDir, + static_cast(Mode), + DetailedPreprocessingRecord, + ImportForwardDeclarations, + InferImportAsMember, + DisableSwiftBridgeAttr, + DisableOverlayModules); + } + }; + } // end namespace swift #endif // SWIFT_BASIC_LANGOPTIONS_H diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index a2733ffffeca3..9efa52313e112 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -115,7 +115,7 @@ class ClangImporter final : public ClangModuleLoader { private: Implementation &Impl; - ClangImporter(ASTContext &ctx, const ClangImporterOptions &clangImporterOpts, + ClangImporter(ASTContext &ctx, DependencyTracker *tracker, DWARFImporterDelegate *dwarfImporterDelegate); @@ -137,8 +137,6 @@ class ClangImporter final : public ClangModuleLoader { /// \param ctx The ASTContext into which the module will be imported. /// The ASTContext's SearchPathOptions will be used for the Clang importer. /// - /// \param importerOpts The options to use for the Clang importer. - /// /// \param swiftPCHHash A hash of Swift's various options in a compiler /// invocation, used to create a unique Bridging PCH if requested. /// @@ -150,12 +148,12 @@ class ClangImporter final : public ClangModuleLoader { /// \returns a new Clang module importer, or null (with a diagnostic) if /// an error occurred. static std::unique_ptr - create(ASTContext &ctx, const ClangImporterOptions &importerOpts, + create(ASTContext &ctx, std::string swiftPCHHash = "", DependencyTracker *tracker = nullptr, DWARFImporterDelegate *dwarfImporterDelegate = nullptr); static std::vector - getClangArguments(ASTContext &ctx, const ClangImporterOptions &importerOpts); + getClangArguments(ASTContext &ctx); static std::unique_ptr createClangInvocation(ClangImporter *importer, diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h deleted file mode 100644 index 173abc210f560..0000000000000 --- a/include/swift/ClangImporter/ClangImporterOptions.h +++ /dev/null @@ -1,133 +0,0 @@ -//===--- ClangImporterOptions.h ---------------------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H -#define SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H - -#include "llvm/ADT/Hashing.h" - -#include -#include - -namespace swift { - -/// Options for controlling the behavior of the Clang importer. -class ClangImporterOptions { -public: - /// The module cache path which the Clang importer should use. - std::string ModuleCachePath; - - /// Extra arguments which should be passed to the Clang importer. - std::vector ExtraArgs; - - /// A directory for overriding Clang's resource directory. - std::string OverrideResourceDir; - - /// The target CPU to compile for. - /// - /// Equivalent to Clang's -mcpu=. - std::string TargetCPU; - - /// The path to which we should store indexing data, if any. - std::string IndexStorePath; - - /// The bridging header or PCH that will be imported. - std::string BridgingHeader; - - /// When automatically generating a precompiled header from the bridging - /// header, place it in this directory. - std::string PrecompiledHeaderOutputDir; - - /// The optimizaton setting. This doesn't typically matter for - /// import, but it can affect Clang's IR generation of static functions. - std::string Optimization; - - /// Disable validating the persistent PCH. - bool PCHDisableValidation = false; - - /// \see Mode - enum class Modes : uint8_t { - /// Set up Clang for importing modules into Swift and generating IR from - /// Swift code. - Normal, - /// Set up Clang for backend compilation only. - EmbedBitcode, - /// Set up Clang to emit a precompiled module from a C/Objective-C module - /// map or dump debugging info about a precompiled module. - PrecompiledModule - }; - - /// Controls how Clang is initially set up. - Modes Mode = Modes::Normal; - - /// When set, preserves more information during import. - /// - /// Also \em disables some information that is only needed for object file - /// generation. - bool DetailedPreprocessingRecord = false; - - /// If true, Clang diagnostics will be dumped to stderr using Clang's - /// diagnostic printer as well as being passed to Swift's diagnostic engine. - bool DumpClangDiagnostics = false; - - /// If true, forward declarations will be imported using unavailable types - /// instead of dropped altogether when possible. - bool ImportForwardDeclarations = false; - - /// Whether to use the import as member inference system - /// - /// When importing a global, try to infer whether we can import it as a - /// member of some type instead. This includes inits, computed properties, - /// and methods. - bool InferImportAsMember = false; - - /// If true ignore the swift bridged attribute. - bool DisableSwiftBridgeAttr = false; - - /// When set, don't look for or load overlays. - bool DisableOverlayModules = false; - - /// When set, don't enforce warnings with -Werror. - bool DebuggerSupport = false; - - /// When set, ClangImporter is disabled, and all requests go to the - /// DWARFImporter delegate. - bool DisableSourceImport = false; - - /// When set, use ExtraArgs alone to configure clang instance because ExtraArgs - /// contains the full option set. - bool ExtraArgsOnly = false; - - /// Return a hash code of any components from these options that should - /// contribute to a Swift Bridging PCH hash. - llvm::hash_code getPCHHashComponents() const { - using llvm::hash_combine; - using llvm::hash_combine_range; - - return hash_combine(ModuleCachePath, - hash_combine_range(ExtraArgs.begin(), ExtraArgs.end()), - OverrideResourceDir, - TargetCPU, - BridgingHeader, - PrecompiledHeaderOutputDir, - static_cast(Mode), - DetailedPreprocessingRecord, - ImportForwardDeclarations, - InferImportAsMember, - DisableSwiftBridgeAttr, - DisableOverlayModules); - } -}; - -} // end namespace swift - -#endif diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 39ab041dbcc1b..c33e9ee9f46fa 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -30,7 +30,6 @@ #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Frontend/DiagnosticVerifier.h" #include "swift/Frontend/FrontendOptions.h" #include "swift/Frontend/ModuleInterfaceSupport.h" diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7a4648f45a459..4a776d6dbb790 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -548,6 +548,7 @@ void ASTContext::operator delete(void *Data) throw() { ASTContext *ASTContext::get(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) { // If more than two data structures are concatentated, then the aggregate @@ -561,15 +562,19 @@ ASTContext *ASTContext::get(LangOptions &langOpts, llvm::alignAddr(impl, llvm::Align(alignof(Implementation)))); new (impl) Implementation(); return new (mem) - ASTContext(langOpts, typeckOpts, SearchPathOpts, SourceMgr, Diags); + ASTContext(langOpts, typeckOpts, SearchPathOpts, ClangImporterOpts, + SourceMgr, Diags); } ASTContext::ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, + ClangImporterOptions &ClangImporterOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) : LangOpts(langOpts), TypeCheckerOpts(typeckOpts), - SearchPathOpts(SearchPathOpts), SourceMgr(SourceMgr), Diags(Diags), + SearchPathOpts(SearchPathOpts), + ClangImporterOpts(ClangImporterOpts), + SourceMgr(SourceMgr), Diags(Diags), evaluator(Diags, langOpts), TheBuiltinModule(createBuiltinModule(*this)), StdlibModuleName(getIdentifier(STDLIB_NAME)), diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 3ec0473562c69..da5b09347ef9c 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -32,7 +32,6 @@ #include "swift/Basic/Range.h" #include "swift/Basic/StringExtras.h" #include "swift/Basic/Version.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Config.h" #include "swift/Demangling/Demangle.h" @@ -410,11 +409,10 @@ bool ClangImporter::Implementation::shouldIgnoreBridgeHeaderTopLevelDecl( } ClangImporter::ClangImporter(ASTContext &ctx, - const ClangImporterOptions &clangImporterOpts, DependencyTracker *tracker, DWARFImporterDelegate *dwarfImporterDelegate) : ClangModuleLoader(tracker), - Impl(*new Implementation(ctx, clangImporterOpts, dwarfImporterDelegate)) { + Impl(*new Implementation(ctx, dwarfImporterDelegate)) { } ClangImporter::~ClangImporter() { @@ -466,12 +464,11 @@ getGlibcModuleMapPath(SearchPathOptions& Opts, llvm::Triple triple, void importer::getNormalInvocationArguments( std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + ASTContext &ctx) { const auto &LangOpts = ctx.LangOpts; const llvm::Triple &triple = LangOpts.Target; SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; - + ClangImporterOptions &importerOpts = ctx.ClangImporterOpts; auto languageVersion = ctx.LangOpts.EffectiveLanguageVersion; if (llvm::sys::path::extension(importerOpts.BridgingHeader) @@ -688,8 +685,7 @@ importer::getNormalInvocationArguments( static void getEmbedBitcodeInvocationArguments(std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + ASTContext &ctx) { invocationArgStrs.insert(invocationArgStrs.end(), { // Backend mode. "-fembed-bitcode", @@ -704,11 +700,11 @@ getEmbedBitcodeInvocationArguments(std::vector &invocationArgStrs, void importer::addCommonInvocationArguments( std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + ASTContext &ctx) { using ImporterImpl = ClangImporter::Implementation; const llvm::Triple &triple = ctx.LangOpts.Target; SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; + const ClangImporterOptions &importerOpts = ctx.ClangImporterOpts; invocationArgStrs.push_back("-target"); invocationArgStrs.push_back(triple.str()); @@ -920,25 +916,24 @@ ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions, } std::vector -ClangImporter::getClangArguments(ASTContext &ctx, - const ClangImporterOptions &importerOpts) { - if (importerOpts.ExtraArgsOnly) { - return importerOpts.ExtraArgs; +ClangImporter::getClangArguments(ASTContext &ctx) { + if (ctx.ClangImporterOpts.ExtraArgsOnly) { + return ctx.ClangImporterOpts.ExtraArgs; } std::vector invocationArgStrs; // Clang expects this to be like an actual command line. So we need to pass in // "clang" for argv[0] invocationArgStrs.push_back("clang"); - switch (importerOpts.Mode) { + switch (ctx.ClangImporterOpts.Mode) { case ClangImporterOptions::Modes::Normal: case ClangImporterOptions::Modes::PrecompiledModule: - getNormalInvocationArguments(invocationArgStrs, ctx, importerOpts); + getNormalInvocationArguments(invocationArgStrs, ctx); break; case ClangImporterOptions::Modes::EmbedBitcode: - getEmbedBitcodeInvocationArguments(invocationArgStrs, ctx, importerOpts); + getEmbedBitcodeInvocationArguments(invocationArgStrs, ctx); break; } - addCommonInvocationArguments(invocationArgStrs, ctx, importerOpts); + addCommonInvocationArguments(invocationArgStrs, ctx); return invocationArgStrs; } @@ -979,12 +974,13 @@ ArrayRef ClangImporter::getExtraClangArgs() const { } std::unique_ptr -ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts, +ClangImporter::create(ASTContext &ctx, std::string swiftPCHHash, DependencyTracker *tracker, DWARFImporterDelegate *dwarfImporterDelegate) { std::unique_ptr importer{ - new ClangImporter(ctx, importerOpts, tracker, dwarfImporterDelegate)}; - importer->Impl.ClangArgs = getClangArguments(ctx, importerOpts); + new ClangImporter(ctx, tracker, dwarfImporterDelegate)}; + auto &importerOpts = ctx.ClangImporterOpts; + importer->Impl.ClangArgs = getClangArguments(ctx); ArrayRef invocationArgStrs = importer->Impl.ClangArgs; importer->Impl.ExtraClangArgs = importerOpts.ExtraArgs; if (importerOpts.DumpClangDiagnostics) { @@ -2016,20 +2012,20 @@ bool PlatformAvailability::treatDeprecatedAsUnavailable( } ClangImporter::Implementation::Implementation( - ASTContext &ctx, const ClangImporterOptions &opts, + ASTContext &ctx, DWARFImporterDelegate *dwarfImporterDelegate) : SwiftContext(ctx), - ImportForwardDeclarations(opts.ImportForwardDeclarations), - InferImportAsMember(opts.InferImportAsMember), - DisableSwiftBridgeAttr(opts.DisableSwiftBridgeAttr), - BridgingHeaderExplicitlyRequested(!opts.BridgingHeader.empty()), - DisableOverlayModules(opts.DisableOverlayModules), + ImportForwardDeclarations(ctx.ClangImporterOpts.ImportForwardDeclarations), + InferImportAsMember(ctx.ClangImporterOpts.InferImportAsMember), + DisableSwiftBridgeAttr(ctx.ClangImporterOpts.DisableSwiftBridgeAttr), + BridgingHeaderExplicitlyRequested(!ctx.ClangImporterOpts.BridgingHeader.empty()), + DisableOverlayModules(ctx.ClangImporterOpts.DisableOverlayModules), IsReadingBridgingPCH(false), CurrentVersion(ImportNameVersion::fromOptions(ctx.LangOpts)), BridgingHeaderLookupTable(new SwiftLookupTable(nullptr)), BuffersForDiagnostics(ctx.SourceMgr), platformAvailability(ctx.LangOpts), nameImporter(), - DisableSourceImport(opts.DisableSourceImport), + DisableSourceImport(ctx.ClangImporterOpts.DisableSourceImport), DWARFImporter(dwarfImporterDelegate) {} ClangImporter::Implementation::~Implementation() { diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index c465b1eb2473c..fbc693e5b22ef 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -16,7 +16,6 @@ #include "ImporterImpl.h" #include "swift/AST/ModuleDependencies.h" #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" #include "llvm/Support/FileSystem.h" @@ -105,9 +104,7 @@ namespace { // adds search paths to Clang's data structures rather than to its // command line. static void addSearchPathInvocationArguments( - std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts) { + std::vector &invocationArgStrs, ASTContext &ctx) { SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; for (const auto &framepath : searchPathOpts.FrameworkSearchPaths) { invocationArgStrs.push_back(framepath.IsSystem ? "-iframework" : "-F"); @@ -123,15 +120,14 @@ static void addSearchPathInvocationArguments( /// Create the command line for Clang dependency scanning. static std::vector getClangDepScanningInvocationArguments( ASTContext &ctx, - const ClangImporterOptions &importerOpts, StringRef sourceFileName) { std::vector commandLineArgs; // Form the basic command line. commandLineArgs.push_back("clang"); - importer::getNormalInvocationArguments(commandLineArgs, ctx, importerOpts); - importer::addCommonInvocationArguments(commandLineArgs, ctx, importerOpts); - addSearchPathInvocationArguments(commandLineArgs, ctx, importerOpts); + importer::getNormalInvocationArguments(commandLineArgs, ctx); + importer::addCommonInvocationArguments(commandLineArgs, ctx); + addSearchPathInvocationArguments(commandLineArgs, ctx); auto sourceFilePos = std::find( commandLineArgs.begin(), commandLineArgs.end(), @@ -303,16 +299,11 @@ Optional ClangImporter::getModuleDependencies( // FIXME: Emit a diagnostic here. return None; } - // Reform the Clang importer options. - // FIXME: Just save a reference or copy so we can get this back. - ClangImporterOptions importerOpts; - importerOpts.ExtraArgs = getExtraClangArgs(); // Determine the command-line arguments for dependency scanning. auto &ctx = Impl.SwiftContext; std::vector commandLineArgs = - getClangDepScanningInvocationArguments( - ctx, importerOpts, *importHackFile); + getClangDepScanningInvocationArguments(ctx, *importHackFile); std::string workingDir = ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get(); @@ -347,19 +338,13 @@ bool ClangImporter::addBridgingHeaderDependencies( // Retrieve or create the shared state. auto clangImpl = getOrCreateClangImpl(cache); - // Reform the Clang importer options. - // FIXME: Just save a reference or copy so we can get this back. - ClangImporterOptions importerOpts; - importerOpts.ExtraArgs = getExtraClangArgs(); - // Retrieve the bridging header. std::string bridgingHeader = *targetModule.getBridgingHeader(); // Determine the command-line arguments for dependency scanning. auto &ctx = Impl.SwiftContext; std::vector commandLineArgs = - getClangDepScanningInvocationArguments( - ctx, importerOpts, bridgingHeader); + getClangDepScanningInvocationArguments(ctx, bridgingHeader); std::string workingDir = ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get(); diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index fc0313bbc91df..ff95d8a106441 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -29,7 +29,6 @@ #include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" #include "swift/Basic/StringExtras.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Parser.h" #include "swift/Strings.h" #include "clang/AST/ASTContext.h" diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 977b2b268d726..e5e1598e2cffb 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -313,7 +313,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation using Version = importer::ImportNameVersion; public: - Implementation(ASTContext &ctx, const ClangImporterOptions &opts, + Implementation(ASTContext &ctx, DWARFImporterDelegate *dwarfImporterDelegate); ~Implementation(); @@ -1430,13 +1430,11 @@ bool isSpecialUIKitStructZeroProperty(const clang::NamedDecl *decl); /// Add command-line arguments for a normal import of Clang code. void getNormalInvocationArguments(std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts); + ASTContext &ctx); /// Add command-line arguments common to all imports of Clang code. void addCommonInvocationArguments(std::vector &invocationArgStrs, - ASTContext &ctx, - const ClangImporterOptions &importerOpts); + ASTContext &ctx); /// Finds a particular kind of nominal by looking through typealiases. template diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 688acbf0b29dd..55999795522b8 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -204,7 +204,9 @@ bool CompilerInstance::setUpASTContextIfNeeded() { Context.reset(ASTContext::get( Invocation.getLangOptions(), Invocation.getTypeCheckerOptions(), - Invocation.getSearchPathOptions(), SourceMgr, Diagnostics)); + Invocation.getSearchPathOptions(), + Invocation.getClangImporterOptions(), + SourceMgr, Diagnostics)); registerParseRequestFunctions(Context->evaluator); registerTypeCheckerRequestFunctions(Context->evaluator); registerSILGenRequestFunctions(Context->evaluator); @@ -481,8 +483,8 @@ bool CompilerInstance::setUpModuleLoaders() { // Otherwise, we just keep it around as our interface to Clang's ABI // knowledge. std::unique_ptr clangImporter = - ClangImporter::create(*Context, Invocation.getClangImporterOptions(), - Invocation.getPCHHash(), getDependencyTracker()); + ClangImporter::create(*Context, Invocation.getPCHHash(), + getDependencyTracker()); if (!clangImporter) { Diagnostics.diagnose(SourceLoc(), diag::error_clang_importer_create_fail); return true; diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 1aeffb3304356..5b3c891bfacae 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -323,8 +323,10 @@ bool CompletionInstance::performCachedOperationIfPossible( TypeCheckerOptions typeckOpts = CI.getASTContext().TypeCheckerOpts; SearchPathOptions searchPathOpts = CI.getASTContext().SearchPathOpts; DiagnosticEngine tmpDiags(tmpSM); + ClangImporterOptions clangOpts; std::unique_ptr tmpCtx( - ASTContext::get(langOpts, typeckOpts, searchPathOpts, tmpSM, tmpDiags)); + ASTContext::get(langOpts, typeckOpts, searchPathOpts, clangOpts, tmpSM, + tmpDiags)); registerParseRequestFunctions(tmpCtx->evaluator); registerIDERequestFunctions(tmpCtx->evaluator); registerTypeCheckerRequestFunctions(tmpCtx->evaluator); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 25161aabaa9ee..00282363d56c8 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1190,6 +1190,7 @@ struct ParserUnit::Implementation { LangOptions LangOpts; TypeCheckerOptions TypeCheckerOpts; SearchPathOptions SearchPathOpts; + ClangImporterOptions clangImporterOpts; DiagnosticEngine Diags; ASTContext &Ctx; SourceFile *SF; @@ -1201,8 +1202,8 @@ struct ParserUnit::Implementation { std::shared_ptr spActions) : SPActions(std::move(spActions)), LangOpts(Opts), TypeCheckerOpts(TyOpts), Diags(SM), - Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, SM, - Diags)) { + Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, + clangImporterOpts, SM, Diags)) { auto parsingOpts = SourceFile::getDefaultParsingOptions(LangOpts); parsingOpts |= ParsingFlags::DisableDelayedBodies; parsingOpts |= ParsingFlags::DisablePoundIfEvaluation; diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp index 510cf5d3edabf..3ef145ad07e3a 100644 --- a/tools/driver/modulewrap_main.cpp +++ b/tools/driver/modulewrap_main.cpp @@ -176,15 +176,15 @@ int modulewrap_main(ArrayRef Args, const char *Argv0, SourceManager SrcMgr; TypeCheckerOptions TypeCheckOpts; LangOptions LangOpts; + ClangImporterOptions ClangImporterOpts; LangOpts.Target = Invocation.getTargetTriple(); ASTContext &ASTCtx = *ASTContext::get(LangOpts, TypeCheckOpts, SearchPathOpts, - SrcMgr, Instance.getDiags()); + ClangImporterOpts, SrcMgr, + Instance.getDiags()); registerParseRequestFunctions(ASTCtx.evaluator); registerTypeCheckerRequestFunctions(ASTCtx.evaluator); - ClangImporterOptions ClangImporterOpts; - ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ClangImporterOpts, ""), - true); + ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ""), true); ModuleDecl *M = ModuleDecl::create(ASTCtx.getIdentifier("swiftmodule"), ASTCtx); SILOptions SILOpts; std::unique_ptr TC(new Lowering::TypeConverter(*M)); diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index b6ba713b59416..05ec2909a02fe 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -2355,8 +2355,7 @@ static bool readBreakageAllowlist(SDKContext &Ctx, llvm::StringSet<> &lines) { invok.setModuleName("ForClangImporter"); if (instance.setup(invok)) return 1; - ClangImporterOptions impOpts; - auto importer = ClangImporter::create(instance.getASTContext(), impOpts); + auto importer = ClangImporter::create(instance.getASTContext()); SmallString<128> preprocessedFilePath; if (auto error = llvm::sys::fs::createTemporaryFile( "breakage-allowlist-", "txt", preprocessedFilePath)) { diff --git a/unittests/AST/TestContext.cpp b/unittests/AST/TestContext.cpp index 7b86295f5c179..174cf90630097 100644 --- a/unittests/AST/TestContext.cpp +++ b/unittests/AST/TestContext.cpp @@ -34,8 +34,8 @@ static Decl *createOptionalType(ASTContext &ctx, SourceFile *fileForLookups, } TestContext::TestContext(ShouldDeclareOptionalTypes optionals) - : Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, SourceMgr, - Diags)) { + : Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, + ClangImporterOpts, SourceMgr, Diags)) { registerParseRequestFunctions(Ctx.evaluator); registerTypeCheckerRequestFunctions(Ctx.evaluator); auto stdlibID = Ctx.getIdentifier(STDLIB_NAME); diff --git a/unittests/AST/TestContext.h b/unittests/AST/TestContext.h index 46aa8d985b62b..90d1ace676afe 100644 --- a/unittests/AST/TestContext.h +++ b/unittests/AST/TestContext.h @@ -29,6 +29,7 @@ class TestContextBase { LangOptions LangOpts; TypeCheckerOptions TypeCheckerOpts; SearchPathOptions SearchPathOpts; + ClangImporterOptions ClangImporterOpts; SourceManager SourceMgr; DiagnosticEngine Diags; diff --git a/unittests/ClangImporter/ClangImporterTests.cpp b/unittests/ClangImporter/ClangImporterTests.cpp index e353fba57745f..94e46f4cee09b 100644 --- a/unittests/ClangImporter/ClangImporterTests.cpp +++ b/unittests/ClangImporter/ClangImporterTests.cpp @@ -5,7 +5,6 @@ #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangImporterOptions.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -75,8 +74,9 @@ TEST(ClangImporterTest, emitPCHInMemory) { swift::SourceManager sourceMgr; swift::DiagnosticEngine diags(sourceMgr); std::unique_ptr context( - ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags)); - auto importer = ClangImporter::create(*context, options); + ASTContext::get(langOpts, typeckOpts, searchPathOpts, options, + sourceMgr, diags)); + auto importer = ClangImporter::create(*context); std::string PCH = createFilename(cache, "bridging.h.pch"); ASSERT_FALSE(importer->canReadPCH(PCH)); diff --git a/unittests/FrontendTool/ModuleLoadingTests.cpp b/unittests/FrontendTool/ModuleLoadingTests.cpp index 7185ffed81ded..0d80267cd90a9 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -98,8 +98,10 @@ class ModuleInterfaceLoaderTest : public testing::Test { LangOptions langOpts; langOpts.Target = llvm::Triple(llvm::sys::getDefaultTargetTriple()); SearchPathOptions searchPathOpts; + ClangImporterOptions clangImpOpts; auto ctx = - ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags); + ASTContext::get(langOpts, typeckOpts, searchPathOpts, clangImpOpts, + sourceMgr, diags); auto loader = ModuleInterfaceLoader::create( *ctx, cacheDir, prebuiltCacheDir, From 3e7f33971c4be02c37f01c57783a8770fc85ef30 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 25 Aug 2020 23:57:31 -0700 Subject: [PATCH 505/663] [ModuleTrace] Handle cycle detection edge case in module trace emission (ep2). Fixes rdar://67704000. --- lib/FrontendTool/FrontendTool.cpp | 130 ++++++++++++++---- .../loaded_module_trace_directness_2.swift | 10 +- 2 files changed, 106 insertions(+), 34 deletions(-) diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index cfeddc5af96a4..8f9f4aa671a69 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -85,6 +85,7 @@ #include "llvm/Support/YAMLTraits.h" #include "llvm/Target/TargetMachine.h" +#include #include #include #include @@ -351,22 +352,25 @@ class ABIDependencyEvaluator { /// Check for cases where we have a fake cycle through an overlay. /// - /// \code - /// Actual stack: - /// sandwichedModule -> Overlay (Swift) -> ... -> sandwichedModule - /// ^^--- wrong! - /// Ideal stack: - /// sandwichedModule -> Underlying (Clang) - /// \endcode + /// Sometimes, we have fake cycles in the import graph due to the Clang + /// importer injecting overlays between Clang modules. These don't represent + /// an actual cycle in the build, so we should ignore them. /// - /// This happens when we have a dependency like: - /// \code - /// Overlay (Swift) -> sandwichedModule -> Underlying (Clang) - /// \endcode + /// We check this lazily after detecting a cycle because it is difficult to + /// determine at the point where we see the overlay whether it was incorrectly + /// injected by the Clang importer or whether any of its imports will + /// eventually lead to a cycle. + /// + /// For more details, see [NOTE: ABIDependencyEvaluator-fake-cycle-detection] /// - /// We check this lazily because eagerly detecting if the dependency on an - /// overlay is correct or not is difficult. - bool isFakeCycleThroughOverlay(ModuleDecl **sandwichedModuleIter); + /// \param startOfCycle A pointer to the element of \c searchStack where + /// the module \em first appeared. + /// + /// \pre The module on top of \c searchStack is the same module as + /// *startOfCycle. + /// + /// \pre searchStack.begin() <= startOfCycle < searchStack.end() + bool isFakeCycleThroughOverlay(ModuleDecl **startOfCycle); /// Recursive step in computing ABI dependencies. /// @@ -492,21 +496,87 @@ bool ABIDependencyEvaluator::isOverlayOfClangModule(ModuleDecl *swiftModule) { return isOverlay; } +// [NOTE: ABIDependencyEvaluator-fake-cycle-detection] +// +// First, let's consider a concrete example. +// - In Clang-land, ToyKit #imports CoreDoll. +// - The Swift overlay for CoreDoll imports both CoreDoll and ToyKit. +// Importing ToyKit from CoreDoll's overlay informally violates the layering +// of frameworks, but it doesn't actually create any cycles in the build +// dependencies. +// ┌───────────────────────────┐ +// ┌───│ CoreDoll.swiftmodule │ +// │ └───────────────────────────┘ +// │ │ +// import ToyKit @_exported import CoreDoll +// │ │ +// │ │ +// ▼ │ +// ┌──────────────────────────┐ │ +// │ ToyKit (ToyKit/ToyKit.h) │ │ +// └──────────────────────────┘ │ +// │ │ +// #import │ +// │ │ +// ▼ │ +// ┌──────────────────────────────┐ │ +// │CoreDoll (CoreDoll/CoreDoll.h)│◀──┘ +// └──────────────────────────────┘ +// +// Say we are trying to build a Swift module that imports ToyKit. Due to how +// module loading works, the Clang importer inserts the CoreDoll overlay +// between the ToyKit and CoreDoll Clang modules, creating a cycle in the +// import graph. +// +// ┌──────────────────────────┐ +// │ ToyKit (ToyKit/ToyKit.h) │◀──────────┐ +// └──────────────────────────┘ │ +// │ │ +// #import import ToyKit +// │ │ +// ▼ │ +// ┌────────────────────────────┐ │ +// │ CoreDoll.swiftmodule │─────────┘ +// └────────────────────────────┘ +// │ +// @_exported import CoreDoll +// │ +// ▼ +// ┌──────────────────────────────┐ +// │CoreDoll (CoreDoll/CoreDoll.h)│ +// └──────────────────────────────┘ +// +// This means that, at some point, searchStack will look like: +// +// [others] → ToyKit → CoreDoll (overlay) → ToyKit +// +// In the general case, there may be arbitrarily many modules in the cycle, +// including submodules. +// +// [others] → ToyKit → [others] → CoreDoll (overlay) → [others] → ToyKit +// +// where "[others]" indicates 0 or more modules of any kind. +// +// To detect this, we check that the start of the cycle is a Clang module and +// that there is at least one overlay between it and its recurrence at the end +// of the searchStack. If so, we assume we have detected a benign cycle which +// can be safely ignored. + bool ABIDependencyEvaluator::isFakeCycleThroughOverlay( - ModuleDecl **sandwichModuleIter) { - assert(sandwichModuleIter >= searchStack.begin() - && sandwichModuleIter < searchStack.end() - && "sandwichModuleIter points to an element in searchStack"); - // The sandwichedModule must be a Clang module. - if (!(*sandwichModuleIter)->isNonSwiftModule()) - return false; - auto nextModuleIter = sandwichModuleIter + 1; - if (nextModuleIter == searchStack.end()) - return false; - // The next module must be a Swift overlay for a Clang module - if ((*nextModuleIter)->isNonSwiftModule()) + ModuleDecl **startOfCycle) { + assert(startOfCycle >= searchStack.begin() && + startOfCycle < searchStack.end() && + "startOfCycleIter points to an element in searchStack"); + // The startOfCycle module must be a Clang module. + if (!(*startOfCycle)->isNonSwiftModule()) return false; - return isOverlayOfClangModule(*nextModuleIter); + // Next, we must have zero or more modules followed by a Swift overlay for a + // Clang module. + return std::any_of(startOfCycle + 1, searchStack.end(), + [this](ModuleDecl *module) { + return !module->isNonSwiftModule() && + isOverlayOfClangModule(module); + }); } void ABIDependencyEvaluator::computeABIDependenciesForModule( @@ -518,7 +588,11 @@ void ABIDependencyEvaluator::computeABIDependenciesForModule( crashOnInvariantViolation([&](llvm::raw_string_ostream &os) { os << "unexpected cycle in import graph!\n"; for (auto m: searchStack) { - printModule(m, os); os << "\ndepends on "; + printModule(m, os); + if (!m->isNonSwiftModule()) { + os << " (isOverlay = " << isOverlayOfClangModule(m) << ")"; + } + os << "\ndepends on "; } printModule(module, os); os << '\n'; }); diff --git a/test/Driver/loaded_module_trace_directness_2.swift b/test/Driver/loaded_module_trace_directness_2.swift index e0b9eabd438bd..79e3ce25223a3 100644 --- a/test/Driver/loaded_module_trace_directness_2.swift +++ b/test/Driver/loaded_module_trace_directness_2.swift @@ -99,16 +99,14 @@ public func runBoth(_ pair: DaemonKit.DaemonPair) { // RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV1 -module-name TestDaemonV1 -emit-loaded-module-trace-path %t/TestDaemonV1.trace.json -I %t/include // RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV1.trace.json -// FIXME: rdar://67704000 -// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include -// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json // RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV3 -module-name TestDaemonV3 -emit-loaded-module-trace-path %t/TestDaemonV3.trace.json -I %t/include // RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV3.trace.json -// FIXME: rdar://67704000 -// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include -// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json +// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include +// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json #if TestDaemon #if V1 From ab83d907ac4942f4d7bc05fef2d20e414af060ed Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 1 Sep 2020 18:25:01 -0400 Subject: [PATCH 506/663] Sema: Fix cycle between closure type computation and EmittedMembersRequest EmittedMembersRequest needs a stable order for synthesized members to ensure that vtable layout is computed consistently across frontend jobs. This used to use the mangled name as the sort key. However, the mangling includes the type of all outer contexts, and if an outer type is a closure, we would need to compute the type of the closure. Computing the type of a closure might require type checking its body though, which would in turn type check the local class, which would invoke EmittedMembersRequest, introducing a cycle. Instead, let's use the DeclName and string-ified type as the sort key. This is simpler to compute than th mangled name, and breaks the cycle. Fixes . --- lib/Sema/TypeCheckDecl.cpp | 16 +++++----------- test/multifile/Inputs/rdar67842221-other.swift | 4 ++++ test/multifile/rdar67842221.swift | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 test/multifile/Inputs/rdar67842221-other.swift create mode 100644 test/multifile/rdar67842221.swift diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 93c9effd91e74..61576f8bf533e 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -25,7 +25,6 @@ #include "TypeCheckType.h" #include "MiscDiagnostics.h" #include "swift/AST/AccessScope.h" -#include "swift/AST/ASTMangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" @@ -2463,21 +2462,16 @@ namespace { // Utility class for deterministically ordering vtable entries for // synthesized methods. struct SortedFuncList { - using Entry = std::pair; + using Key = std::tuple; + using Entry = std::pair; SmallVector elts; bool sorted = false; void add(AbstractFunctionDecl *afd) { - Mangle::ASTMangler mangler; - std::string mangledName; - if (auto *cd = dyn_cast(afd)) - mangledName = mangler.mangleConstructorEntity(cd, /*allocator=*/false); - else if (auto *dd = dyn_cast(afd)) - mangledName = mangler.mangleDestructorEntity(dd, /*deallocating=*/false); - else - mangledName = mangler.mangleEntity(afd); + assert(!isa(afd)); - elts.push_back(std::make_pair(mangledName, afd)); + Key key{afd->getName(), afd->getInterfaceType().getString()}; + elts.emplace_back(key, afd); } bool empty() { return elts.empty(); } diff --git a/test/multifile/Inputs/rdar67842221-other.swift b/test/multifile/Inputs/rdar67842221-other.swift new file mode 100644 index 0000000000000..bda0e894cfc54 --- /dev/null +++ b/test/multifile/Inputs/rdar67842221-other.swift @@ -0,0 +1,4 @@ +let closureValue = { () -> () in + class DummyClass {} + return () +}() diff --git a/test/multifile/rdar67842221.swift b/test/multifile/rdar67842221.swift new file mode 100644 index 0000000000000..64bacf0e58901 --- /dev/null +++ b/test/multifile/rdar67842221.swift @@ -0,0 +1,17 @@ +// Test both orderings, and single-file vs WMO + +// RUN: %target-swift-frontend -emit-ir -primary-file %s %S/Inputs/rdar67842221-other.swift -module-name main +// RUN: %target-swift-frontend -emit-ir %s -primary-file %S/Inputs/rdar67842221-other.swift -module-name main + +// RUN: %target-swift-frontend -emit-ir -primary-file %S/Inputs/rdar67842221-other.swift %s -module-name main +// RUN: %target-swift-frontend -emit-ir %S/Inputs/rdar67842221-other.swift -primary-file %s -module-name main + +// RUN: %target-swift-frontend -emit-ir %S/Inputs/rdar67842221-other.swift %s -module-name main +// RUN: %target-swift-frontend -emit-ir %S/Inputs/rdar67842221-other.swift %s -module-name main + +// The closure defines a local class; we want to make sure there is no cycle +// between computing the semantic members of the local class (which requires +// sorting) and computing the type of the closure value +public func force() { + _ = closureValue +} From 853586fc072d22493116722c61dc57cfa2c363b4 Mon Sep 17 00:00:00 2001 From: Eric Miotto <1094986+edymtt@users.noreply.github.com> Date: Tue, 1 Sep 2020 15:31:33 -0700 Subject: [PATCH 507/663] [build] Reinstate CMAKE_CXX_FLAGS_${CFLAGS_BUILD_TYPE} for LLVM (#33745) Set those at the value pre #33388 -- this would avoid regressions of disk space usage (in particular around building Swift LTO) Addresses rdar://68091272 --- utils/build-script-impl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/build-script-impl b/utils/build-script-impl index ff67887c57fb0..bced37215db7b 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1579,6 +1579,8 @@ for host in "${ALL_HOSTS[@]}"; do "${cmake_options[@]}" -DCMAKE_C_FLAGS="$(llvm_c_flags ${host})" -DCMAKE_CXX_FLAGS="$(llvm_c_flags ${host})" + -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" -DCMAKE_BUILD_TYPE:STRING="${LLVM_BUILD_TYPE}" -DLLVM_TOOL_SWIFT_BUILD:BOOL=NO -DLLVM_TOOL_LLD_BUILD:BOOL=TRUE From 0bc48dea75ce2701ba7a8e43ed85b2f6125905d0 Mon Sep 17 00:00:00 2001 From: Benjamin Barnard <44757473+barnard-b@users.noreply.github.com> Date: Tue, 1 Sep 2020 19:09:39 -0400 Subject: [PATCH 508/663] [stdlib] NFC: Fix typo in comment. --- stdlib/public/core/StringObject.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/StringObject.swift b/stdlib/public/core/StringObject.swift index 30f3989df4699..ebc2ce510be99 100644 --- a/stdlib/public/core/StringObject.swift +++ b/stdlib/public/core/StringObject.swift @@ -293,7 +293,7 @@ extension _StringObject.CountAndFlags { on arm64. */ extension _StringObject.Nibbles { - // The canonical empty sting is an empty small string + // The canonical empty string is an empty small string @inlinable @inline(__always) internal static var emptyString: UInt64 { return _StringObject.Nibbles.small(isASCII: true) From 69eb6ce376b2a514ff264d0b6062c11990c13d15 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sun, 23 Aug 2020 19:38:11 -0700 Subject: [PATCH 509/663] [opt-remark] Add a new SIL testing option that works around not having decls in SIL for debug_value. Instead, in such a case, we use the name on the debug_value instead and just use as the loc the debug_value itself. This will let me write SIL test cases for opt-remark-gen. I am going to add SIL test cases for future changes (as well as swift ones) using this technique. I am going to in forthcoming commits fill in some tests for the current opt-remark-generation here. I just want to get in this part. --- include/swift/SIL/OptimizationRemark.h | 6 ++ .../Transforms/OptRemarkGenerator.cpp | 63 +++++++++++++++---- test/SILOptimizer/opt-remark-generator.sil | 41 +++++++++++- 3 files changed, 97 insertions(+), 13 deletions(-) diff --git a/include/swift/SIL/OptimizationRemark.h b/include/swift/SIL/OptimizationRemark.h index 32842dabb5543..632b6b7e45d19 100644 --- a/include/swift/SIL/OptimizationRemark.h +++ b/include/swift/SIL/OptimizationRemark.h @@ -119,6 +119,12 @@ struct Argument { : Argument(ArgumentKey(ArgumentKeyKind::Default, key), msg, decl) {} Argument(ArgumentKey key, StringRef msg, const ValueDecl *decl) : key(key), val(msg), loc(decl->getLoc()) {} + + Argument(StringRef key, llvm::Twine &&msg, SILLocation loc) + : Argument(ArgumentKey(ArgumentKeyKind::Default, key), std::move(msg), + loc) {} + Argument(ArgumentKey key, llvm::Twine &&msg, SILLocation loc) + : key(key), val(msg.str()), loc(loc.getSourceLoc()) {} }; /// Shorthand to insert named-value pairs. diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index 987c36ed0cc36..22668a8ef01ca 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -41,6 +41,15 @@ static llvm::cl::opt ForceVisitImplicitAutogeneratedFunctions( "Emit opt remarks even on implicit and autogenerated functions"), llvm::cl::init(false)); +static llvm::cl::opt DecllessDebugValueUseSILDebugInfo( + "optremarkgen-declless-debugvalue-use-sildebugvar-info", llvm::cl::Hidden, + llvm::cl::desc( + "If a debug_value does not have a decl, infer a value with a name from " + "that info that has a loc set to the loc of the debug_value " + "instruction itself. This is for testing purposes so it is easier to " + "write SIL test cases for this pass"), + llvm::cl::init(false)); + //===----------------------------------------------------------------------===// // Value To Decl Inferrer //===----------------------------------------------------------------------===// @@ -65,16 +74,13 @@ struct ValueToDeclInferrer { /// accessPath we computed for decl producing a segmented access path, e.x.: /// "of 'x.lhs.ivar'". void printNote(llvm::raw_string_ostream &stream, const ValueDecl *decl); + + void printProjectionPath(llvm::raw_string_ostream &stream); }; } // anonymous namespace -void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, - const ValueDecl *decl) { - assert(decl && - "We assume for now that this is always called with a non-null decl"); - stream << "of '" << decl->getBaseName(); - +void ValueToDeclInferrer::printProjectionPath(llvm::raw_string_ostream &stream) { for (auto &pair : accessPath) { auto baseType = pair.first; auto &proj = pair.second; @@ -111,8 +117,14 @@ void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, llvm_unreachable("Covered switch is not covered?!"); } +} - accessPath.clear(); +void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, + const ValueDecl *decl) { + assert(decl && + "We assume for now that this is always called with a non-null decl"); + stream << "of '" << decl->getBaseName(); + printProjectionPath(stream); stream << "'"; } @@ -145,6 +157,11 @@ static bool hasNonInlinedDebugScope(SILInstruction *i) { bool ValueToDeclInferrer::infer( ArgumentKeyKind keyKind, SILValue value, SmallVectorImpl &resultingInferredDecls) { + // Clear the stored access path at end of scope. + SWIFT_DEFER { + accessPath.clear(); + }; + // This is a linear IR traversal using a 'falling while loop'. That means // every time through the loop we are trying to handle a case before we hit // the bottom of the while loop where we always return true (since we did not @@ -234,15 +251,37 @@ bool ValueToDeclInferrer::infer( llvm::raw_string_ostream stream(msg); printNote(stream, decl); } - resultingInferredDecls.push_back( - Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + resultingInferredDecls.emplace_back( + OptRemark::ArgumentKey{keyKind, "InferredValue"}, + std::move(msg), decl); foundDeclFromUse = true; + } else { + // If we did not have a decl, see if we were asked for testing + // purposes to use SILDebugInfo to create a placeholder inferred + // value. + if (DecllessDebugValueUseSILDebugInfo) { + if (auto varInfo = dvi->getVarInfo()) { + auto name = varInfo->Name; + if (!name.empty()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + stream << "of '" << name; + printProjectionPath(stream); + stream << "'"; + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, + std::move(msg), + dvi->getLoc())); + foundDeclFromUse = true; + } + } + } } } } } - if (foundDeclFromUse) - return true; // At this point, we could not infer any argument. See if we can look // through loads. @@ -267,7 +306,7 @@ bool ValueToDeclInferrer::infer( // If we reached this point, we finished falling through the loop and return // true. - return true; + return foundDeclFromUse; } } diff --git a/test/SILOptimizer/opt-remark-generator.sil b/test/SILOptimizer/opt-remark-generator.sil index b8ddadb6d1ac0..168aee0985fa5 100644 --- a/test/SILOptimizer/opt-remark-generator.sil +++ b/test/SILOptimizer/opt-remark-generator.sil @@ -1,4 +1,4 @@ -// RUN: %target-sil-opt -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null +// RUN: %target-sil-opt -optremarkgen-declless-debugvalue-use-sildebugvar-info -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null sil_stage canonical @@ -6,10 +6,49 @@ import Builtin sil @foo : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { bb0(%0 : $Builtin.NativeObject): + debug_value %0 : $Builtin.NativeObject, let, name "arg" strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-2 {{of 'arg'}} retain_value %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-4 {{of 'arg'}} strong_release %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} + // expected-note @-6 {{of 'arg'}} release_value %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} + // expected-note @-8 {{of 'arg'}} %9999 = tuple() return %9999 : $() } + +public enum TrivialState { +case first +case second +case third +} + +struct StructWithOwner { + var owner: Builtin.NativeObject + var state: TrivialState +} + +sil @extract_out_singleobj_struct_subfield_1 : $@convention(thin) (@guaranteed StructWithOwner) -> Builtin.NativeObject { +bb0(%0 : $StructWithOwner): + debug_value %0 : $StructWithOwner, let, name "x" + %1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner + strong_retain %1 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-3 {{of 'x.owner'}} + return %1 : $Builtin.NativeObject +} + +// This case should never actually happen like this, but we should handle it in +// a sane way by printing both notes for y and x and also make sure that we do +// not infer .owner on y since y is on owner itself. +sil @extract_out_singleobj_struct_subfield_multiple_debugvalue : $@convention(thin) (@guaranteed StructWithOwner) -> Builtin.NativeObject { +bb0(%0 : $StructWithOwner): + debug_value %0 : $StructWithOwner, let, name "x" + %1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner + debug_value %1 : $Builtin.NativeObject, let, name "y" + strong_retain %1 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-4 {{of 'x.owner'}} + // expected-note @-3 {{of 'y'}} + return %1 : $Builtin.NativeObject +} From 5bf15f81b1b92b79187798a5a4e31f09e7879a60 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Tue, 1 Sep 2020 20:20:09 -0700 Subject: [PATCH 510/663] Add a -ignore-always-inline frontend flag which ignores @inline(__always) attributes. (#33466) --- include/swift/AST/SILOptions.h | 5 ++ include/swift/Option/FrontendOptions.td | 3 + lib/Frontend/CompilerInvocation.cpp | 2 + .../Transforms/PerformanceInliner.cpp | 19 +++-- test/SILOptimizer/ignore-always-inline.sil | 71 +++++++++++++++++++ tools/sil-opt/SILOpt.cpp | 6 ++ 6 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 test/SILOptimizer/ignore-always-inline.sil diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index af8d8c29f2c69..5eaac7a1cf721 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -128,6 +128,11 @@ class SILOptions { /// Assume that code will be executed in a single-threaded environment. bool AssumeSingleThreaded = false; + /// Turn @inline(__always) attributes into no-ops. + /// + /// For experimentation around code size reduction. + bool IgnoreAlwaysInline = false; + /// Indicates which sanitizer is turned on. OptionSet Sanitizers; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 8996c6119e5d3..c55ca598baff7 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -601,6 +601,9 @@ def disable_incremental_llvm_codegeneration : Flag<["-"], "disable-incremental-llvm-codegen">, HelpText<"Disable incremental llvm code generation.">; +def ignore_always_inline : Flag<["-"], "ignore-always-inline">, + HelpText<"Ignore @inline(__always) attributes.">; + def emit_sorted_sil : Flag<["-"], "emit-sorted-sil">, HelpText<"When printing SIL, print out all sil entities sorted by name to " "ease diffing">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 421fe050a6a3b..7bc56692e25bc 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1128,6 +1128,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, Opts.AssumeSingleThreaded = true; } + Opts.IgnoreAlwaysInline |= Args.hasArg(OPT_ignore_always_inline); + // Parse the assert configuration identifier. if (const Arg *A = Args.getLastArg(OPT_AssertConfig)) { StringRef Configuration = A->getValue(); diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp index e07553e784ef4..ce3a00e413754 100644 --- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp +++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp @@ -559,6 +559,15 @@ static bool returnsClosure(SILFunction *F) { return false; } +static bool isInlineAlwaysCallSite(SILFunction *Callee) { + if (Callee->isTransparent()) + return true; + if (Callee->getInlineStrategy() == AlwaysInline) + if (!Callee->getModule().getOptions().IgnoreAlwaysInline) + return true; + return false; +} + /// Checks if a given generic apply should be inlined unconditionally, i.e. /// without any complex analysis using e.g. a cost model. /// It returns true if a function should be inlined. @@ -585,7 +594,7 @@ static Optional shouldInlineGeneric(FullApplySite AI) { // Always inline generic functions which are marked as // AlwaysInline or transparent. - if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) + if (isInlineAlwaysCallSite(Callee)) return true; // If all substitutions are concrete, then there is no need to perform the @@ -632,7 +641,7 @@ bool SILPerformanceInliner::decideInWarmBlock( SILFunction *Callee = AI.getReferencedFunctionOrNull(); - if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) { + if (isInlineAlwaysCallSite(Callee)) { LLVM_DEBUG(dumpCaller(AI.getFunction()); llvm::dbgs() << " always-inline decision " << Callee->getName() << '\n'); @@ -655,7 +664,7 @@ bool SILPerformanceInliner::decideInColdBlock(FullApplySite AI, return false; } - if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) { + if (isInlineAlwaysCallSite(Callee)) { LLVM_DEBUG(dumpCaller(AI.getFunction()); llvm::dbgs() << " always-inline decision " << Callee->getName() << '\n'); @@ -717,10 +726,6 @@ addToBBCounts(llvm::DenseMap &BBToWeightMap, } } -static bool isInlineAlwaysCallSite(SILFunction *Callee) { - return Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent(); -} - static void calculateBBWeights(SILFunction *Caller, DominanceInfo *DT, llvm::DenseMap &BBToWeightMap) { diff --git a/test/SILOptimizer/ignore-always-inline.sil b/test/SILOptimizer/ignore-always-inline.sil new file mode 100644 index 0000000000000..49d98e870a4f1 --- /dev/null +++ b/test/SILOptimizer/ignore-always-inline.sil @@ -0,0 +1,71 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -dce | %FileCheck %s -check-prefix=REGULAR +// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -dce -ignore-always-inline | %FileCheck %s -check-prefix=IGNORED + +sil_stage canonical + +// REGULAR: sil [Osize] @caller +// IGNORED: sil [Osize] @caller +sil [Osize] @caller : $@convention(thin) () -> () { +bb0: + // REGULAR-NOT: function_ref @callee + // REGULAR: function_ref @foobar + // IGNORED: function_ref @callee + %d1 = function_ref @callee : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + + %9999 = tuple() + return %9999 : $() +} + +sil @foobar : $@convention(thin) () -> () + +// callee is "expensive" enough to not get inlined unless [always_inline] is used +// REGULAR: sil [always_inline] [Osize] @callee +// IGNORED: sil [always_inline] [Osize] @callee +sil [always_inline] [Osize] @callee : $@convention(thin) () -> () { +bb0: + %d1 = function_ref @foobar : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + apply %d1() : $@convention(thin) () -> () + + %9999 = tuple() + return %9999 : $() +} diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index 490bf85550abb..f4d2b4490cf3b 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -274,6 +274,11 @@ static llvm::cl::opt llvm::cl::desc("Enable C++ interop."), llvm::cl::init(false)); +static llvm::cl::opt + IgnoreAlwaysInline("ignore-always-inline", + llvm::cl::desc("Ignore [always_inline] attribute."), + llvm::cl::init(false)); + static void runCommandLineSelectedPasses(SILModule *Module, irgen::IRGenModule *IRGenMod) { auto &opts = Module->getOptions(); @@ -398,6 +403,7 @@ int main(int argc, char **argv) { } SILOpts.EnableSpeculativeDevirtualization = EnableSpeculativeDevirtualization; + SILOpts.IgnoreAlwaysInline = IgnoreAlwaysInline; serialization::ExtendedValidationInfo extendedInfo; llvm::ErrorOr> FileBufOrErr = From 38dd7d81922ff764b0f83e501ab748dcbd6694bc Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Tue, 4 Aug 2020 17:28:56 -0400 Subject: [PATCH 511/663] [IRGen] Fix asserting local extern declarations. emitClangDecl interacts with clang and LLVM to achieve C interop. On the LLVM side, CodeGenModule::EmitGlobal asserts if the decl eventually passed to it is not a "file scoped" via VarDecl::isFileVarDecl. LLVM currently asserts on local extern variables in C headers passed to Swift when the definition exists outside that header. To fix this, we need to ensure that we are only passing Decls that do not trip the assertion but not unduly limit local extern variables when the corresponding definition exists inside that header. We can do that fairly simply by checking for isFileVarDecl just before we hand-off to clang. When the definition for the local extern variable exists inside the header, isFileVarDecl is true, and if it exists elsewhere, it is false. This matches up with the assert expectation on the LLVM side exactly. This indirectly addresses #28968, since that contains the only part of the Swift stdlib that uses a local extern variable, but any header that is used with Swift that contains a local extern variable will cause the compiler to assert when built with assertions enabled. --- lib/IRGen/GenClangDecl.cpp | 5 +++++ test/IRGen/Inputs/local_extern.h | 21 +++++++++++++++++++++ test/IRGen/local_extern.swift | 10 ++++++++++ 3 files changed, 36 insertions(+) create mode 100644 test/IRGen/Inputs/local_extern.h create mode 100644 test/IRGen/local_extern.swift diff --git a/lib/IRGen/GenClangDecl.cpp b/lib/IRGen/GenClangDecl.cpp index 577307ce502d9..7679773935bf4 100644 --- a/lib/IRGen/GenClangDecl.cpp +++ b/lib/IRGen/GenClangDecl.cpp @@ -98,6 +98,11 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) { refFinder.TraverseDecl(executableDecl); next = executableDecl; } + + if (auto var = dyn_cast(next)) + if (!var->isFileVarDecl()) + continue; + ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(next)); } } diff --git a/test/IRGen/Inputs/local_extern.h b/test/IRGen/Inputs/local_extern.h new file mode 100644 index 0000000000000..de84f094bee45 --- /dev/null +++ b/test/IRGen/Inputs/local_extern.h @@ -0,0 +1,21 @@ +static inline int _no_prior_var() { + extern int var; + return var; +} + +static inline int _no_prior_func() { + extern int func(); + return func(); +} + +static int prior_var = 1; +static inline int _prior_var() { + extern int prior_var; + return prior_var; +} + +static inline int prior_func() { return 1; } +static inline int _prior_func() { + extern int prior_func(); + return prior_func(); +} diff --git a/test/IRGen/local_extern.swift b/test/IRGen/local_extern.swift new file mode 100644 index 0000000000000..4ce7554681491 --- /dev/null +++ b/test/IRGen/local_extern.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -import-objc-header %S/Inputs/local_extern.h %s -emit-ir | %FileCheck %s +// CHECK: @var = external global i32 +// CHECK: @prior_var = internal global i32 +// CHECK: declare i32 @func +// CHECK: define internal i32 @prior_func + +print("\(_no_prior_var())") +print("\(_no_prior_func())") +print("\(_prior_var())") +print("\(_prior_func())") From 2daf1d20500f7f879f7ce071568e7f655c6e4504 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sun, 23 Aug 2020 12:47:33 -0700 Subject: [PATCH 512/663] [opt-remark] When looking for debug_value users, look modulo RC Identity preserving users. A key concept in late ARC optimization is "RC Identity". In short, a result of an instruction is rc-identical to an operand of the instruction if one can safely move a retain (release) from before the instruction on the result to one after on the operand without changing the program semantics. This creates a simple model where one can work on equivalence classes of rc-identical values (using a dominating definition generally as the representative) and thus optimize/pair retain, release. When preparing for late ARC optimization, the optimizer will normalize aggregate ARC operations (retain_value, release_value) into singular strong_retain, strong_release operations on leaf types of the aggregate that are non-trivial. As an example, a retain_value on a KlassPair would be canonicalized into two strong_retain, one for the lhs and one for the rhs. When this is done, the optimizer generally just creates new struct_extract at the point where the retain is. In such a case, we may have that the debug_value for the underlying type is actually on a reformed aggregate whose underlying parts we are retaining: ``` bb0(%0 : $Builtin.NativeObject): strong_retain %0 %1 = struct $Array(%0 : $Builtin.NativeObject, ...) debug_value %1 : $Array, ... ``` By looking through RC identical uses, we can handle a large subset of these cases without much effort: ones were there is a single owning pointer like Array. To handle more complex cases we would have to calculate an inverse access path needed to get back to our value and somehow deal with all of the complexity therein (I am sure we can do it I just haven't thought through all of the details). The only interesting behavior that this results in is that when we emit diagnostics, we just use the rc-identical transitive use debug_value's name without a projection path. This is because the source location associated with that debug_value is with a separate value that is rc-identical to the actual value that we visited during our opt-remark traversal up the def-use graph. Consider the following example below, noting the comments that show in the SIL itself what I attempted to explain above. ``` struct KlassPair { var lhs: Klass var rhs: Klass } struct StateWithOwningPointer { var state: TrivialState var owningPtr: Klass } sil @theFunction : $@convention(thin) () -> () { bb0: %0 = apply %getKlassPair() : $@convention(thin) () -> @owned KlassPair // This debug_value's name can be combined... debug_value %0 : $KlassPair, name "myPair" // ... with the access path from the struct_extract here... %1 = struct_extract %0 : $KlassPair, #KlassPair.lhs // ... to emit a nice diagnostic that 'myPair.lhs' is being retained. strong_retain %1 : $Klass // In contrast in the case below, we rely on looking through rc-identity uses // to find the debug_value. In this case, the source info associated with the // debug_value (%2) is no longer associated with the underlying access path we // have been tracking upwards (%1 is in our access path list). Instead, we // know that the debug_value is rc-identical to whatever value we were // originally tracking up (%1) and thus the correct identifier to use is the // direct name of the identifier alone (without access path) since that source // identifier must be some value in the source that by itself is rc-identical // to whatever is being manipulated. Thus if we were to emit the access path // here for na rc-identical use we would get "myAdditionalState.owningPtr" // which is misleading since ArrayWrapperWithMoreState does not have a field // named 'owningPtr', its subfield array does. That being said since // rc-identity means a retain_value on the value with the debug_value upon it // is equivalent to the access path value we found by walking up the def-use // graph from our strong_retain's operand. %0a = apply %getStateWithOwningPointer() : $@convention(thin) () -> @owned StateWithOwningPointer %1 = struct_extract %0a : $StateWithOwningPointer, #StateWithOwningPointer.owningPtr strong_retain %1 : $Klass %2 = struct $Array(%0 : $Builtin.NativeObject, ...) %3 = struct $ArrayWrapperWithMoreState(%2 : $Array, %moreState : MoreState) debug_value %2 : $ArrayWrapperWithMoreState, name "myAdditionalState" } ``` --- .../Analysis/RCIdentityAnalysis.h | 8 +- .../Analysis/RCIdentityAnalysis.cpp | 11 +- .../Transforms/OptRemarkGenerator.cpp | 195 ++++++++++++------ test/SILOptimizer/opt-remark-generator.sil | 82 +++++--- 4 files changed, 206 insertions(+), 90 deletions(-) diff --git a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h index f4ddc2ee77673..3064fc889abb2 100644 --- a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h @@ -55,7 +55,7 @@ class RCIdentityFunctionInfo { /// *NOTE* This ignores obvious ARC escapes where the a potential /// user of the RC is not managed by ARC. For instance /// unchecked_trivial_bit_cast. - void getRCUses(SILValue V, llvm::SmallVectorImpl &Uses); + void getRCUses(SILValue V, SmallVectorImpl &Uses); /// A helper method that calls getRCUses and then maps each operand to the /// operands user and then uniques the list. @@ -63,7 +63,11 @@ class RCIdentityFunctionInfo { /// *NOTE* The routine asserts that the passed in Users array is empty for /// simplicity. If needed this can be changed, but it is not necessary given /// current uses. - void getRCUsers(SILValue V, llvm::SmallVectorImpl &Users); + void getRCUsers(SILValue V, SmallVectorImpl &Users); + + /// Like getRCUses except uses a callback to prevent the need for an + /// intermediate array. + void visitRCUses(SILValue V, function_ref Visitor); void handleDeleteNotification(SILNode *node) { auto value = dyn_cast(node); diff --git a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp index 7a04927a9dc5a..e9e07a1a13f0a 100644 --- a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp @@ -522,13 +522,18 @@ void RCIdentityFunctionInfo::getRCUsers( /// We only use the instruction analysis here. void RCIdentityFunctionInfo::getRCUses(SILValue InputValue, llvm::SmallVectorImpl &Uses) { + return visitRCUses(InputValue, + [&](Operand *op) { return Uses.push_back(op); }); +} +void RCIdentityFunctionInfo::visitRCUses( + SILValue InputValue, function_ref Visitor) { // Add V to the worklist. - llvm::SmallVector Worklist; + SmallVector Worklist; Worklist.push_back(InputValue); // A set used to ensure we only visit uses once. - llvm::SmallPtrSet VisitedOps; + SmallPtrSet VisitedOps; // Then until we finish the worklist... while (!Worklist.empty()) { @@ -564,7 +569,7 @@ void RCIdentityFunctionInfo::getRCUses(SILValue InputValue, } // Otherwise, stop searching and report this RC operand. - Uses.push_back(Op); + Visitor(Op); } } } diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index 22668a8ef01ca..3b6cb4f116bb9 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -62,6 +62,7 @@ struct ValueToDeclInferrer { RCIdentityFunctionInfo &rcfi; SmallVector, 32> accessPath; + SmallVector rcIdenticalSecondaryUseSearch; ValueToDeclInferrer(RCIdentityFunctionInfo &rcfi) : rcfi(rcfi) {} @@ -70,17 +71,74 @@ struct ValueToDeclInferrer { bool infer(ArgumentKeyKind keyKind, SILValue value, SmallVectorImpl &resultingInferredDecls); - /// Print out a note to \p stream that beings at decl and then consumes the - /// accessPath we computed for decl producing a segmented access path, e.x.: - /// "of 'x.lhs.ivar'". - void printNote(llvm::raw_string_ostream &stream, const ValueDecl *decl); + /// Print out a note to \p stream that beings at decl and then if + /// useProjectionPath is set to true iterates the accessPath we computed for + /// decl producing a segmented access path, e.x.: "of 'x.lhs.ivar'". + /// + /// The reason why one may not want to emit a projection path note here is if + /// one found an debug_value on a value that is rc-identical to the actual + /// value associated with the current projection path. Consider the following + /// SIL: + /// + /// struct KlassPair { + /// var lhs: Klass + /// var rhs: Klass + /// } + /// + /// struct StateWithOwningPointer { + /// var state: TrivialState + /// var owningPtr: Klass + /// } + /// + /// sil @theFunction : $@convention(thin) () -> () { + /// bb0: + /// %0 = apply %getKlassPair() : $@convention(thin) () -> @owned KlassPair + /// // This debug_value's name can be combined... + /// debug_value %0 : $KlassPair, name "myPair" + /// // ... with the access path from the struct_extract here... + /// %1 = struct_extract %0 : $KlassPair, #KlassPair.lhs + /// // ... to emit a nice diagnostic that 'myPair.lhs' is being retained. + /// strong_retain %1 : $Klass + /// + /// // In contrast in this case, we rely on looking through rc-identity + /// // uses to find the debug_value. In this case, the source info + /// // associated with the debug_value (%2) is no longer associated with + /// // the underlying access path we have been tracking upwards (%1 is in + /// // our access path list). Instead, we know that the debug_value is + /// // rc-identical to whatever value we were originally tracking up (%1) + /// // and thus the correct identifier to use is the direct name of the + /// // identifier alone since that source identifier must be some value + /// // in the source that by itself is rc-identical to whatever is being + /// // manipulated. + /// // + /// // The reason why we must do this is due to the behavior of the late + /// // optimizer and how it forms these patterns in the code. + /// %0a = apply %getStateWithOwningPointer() : $@convention(thin) () -> @owned StateWithOwningPointer + /// %1 = struct_extract %0a : $StateWithOwningPointer, #StateWithOwningPointer.owningPtr + /// strong_retain %1 : $Klass + /// %2 = struct $Array(%0 : $Builtin.NativeObject, ...) + /// debug_value %2 : $Array, ... + /// } + void printNote(llvm::raw_string_ostream &stream, StringRef name, + bool shouldPrintAccessPath = true); + + /// Convenience overload that calls: + /// + /// printNote(stream, decl->getBaseName().userFacingName(), shouldPrintAccessPath). + void printNote(llvm::raw_string_ostream &stream, const ValueDecl *decl, + bool shouldPrintAccessPath = true) { + printNote(stream, decl->getBaseName().userFacingName(), + shouldPrintAccessPath); + } - void printProjectionPath(llvm::raw_string_ostream &stream); + /// Print out non-destructively the current access path we have found to + /// stream. + void printAccessPath(llvm::raw_string_ostream &stream); }; } // anonymous namespace -void ValueToDeclInferrer::printProjectionPath(llvm::raw_string_ostream &stream) { +void ValueToDeclInferrer::printAccessPath(llvm::raw_string_ostream &stream) { for (auto &pair : accessPath) { auto baseType = pair.first; auto &proj = pair.second; @@ -120,11 +178,11 @@ void ValueToDeclInferrer::printProjectionPath(llvm::raw_string_ostream &stream) } void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, - const ValueDecl *decl) { - assert(decl && - "We assume for now that this is always called with a non-null decl"); - stream << "of '" << decl->getBaseName(); - printProjectionPath(stream); + StringRef name, + bool shouldPrintAccessPath) { + stream << "of '" << name; + if (shouldPrintAccessPath) + printAccessPath(stream); stream << "'"; } @@ -161,6 +219,7 @@ bool ValueToDeclInferrer::infer( SWIFT_DEFER { accessPath.clear(); }; + SmallPtrSet visitedDebugValueInsts; // This is a linear IR traversal using a 'falling while loop'. That means // every time through the loop we are trying to handle a case before we hit @@ -233,62 +292,77 @@ bool ValueToDeclInferrer::infer( } } - // Then visit our users and see if we can find a debug_value that provides - // us with a decl we can use to construct an argument. + // Then visit our users (ignoring rc identical transformations) and see if + // we can find a debug_value that provides us with a decl we can use to + // construct an argument. + // + // The reason why we do this is that sometimes we reform a struct from its + // constituant parts and then construct the debug_value from that. For + // instance, if we FSOed. bool foundDeclFromUse = false; - for (auto *use : value->getUses()) { + rcfi.visitRCUses(value, [&](Operand *use) { // Skip type dependent uses. if (use->isTypeDependent()) - continue; + return; + + // Then see if we have a debug_value that is associated with a non-inlined + // debug scope. Such an instruction is an instruction that is from the + // current function. + auto *dvi = dyn_cast(use->getUser()); + if (!dvi || !hasNonInlinedDebugScope(dvi)) + return; - if (auto *dvi = dyn_cast(use->getUser())) { - // Check if our debug_value has a decl and was not inlined into the - // current function. - if (hasNonInlinedDebugScope(dvi)) { - if (auto *decl = dvi->getDecl()) { - std::string msg; - { - llvm::raw_string_ostream stream(msg); - printNote(stream, decl); - } - resultingInferredDecls.emplace_back( - OptRemark::ArgumentKey{keyKind, "InferredValue"}, - std::move(msg), decl); - foundDeclFromUse = true; - } else { - // If we did not have a decl, see if we were asked for testing - // purposes to use SILDebugInfo to create a placeholder inferred - // value. - if (DecllessDebugValueUseSILDebugInfo) { - if (auto varInfo = dvi->getVarInfo()) { - auto name = varInfo->Name; - if (!name.empty()) { - std::string msg; - { - llvm::raw_string_ostream stream(msg); - stream << "of '" << name; - printProjectionPath(stream); - stream << "'"; - } - resultingInferredDecls.push_back( - Argument({keyKind, "InferredValue"}, - std::move(msg), - dvi->getLoc())); - foundDeclFromUse = true; - } - } - } - } + // See if we have already inferred this debug_value as a potential source + // for this instruction. In such a case, just return. + if (!visitedDebugValueInsts.insert(dvi).second) + return; + + if (auto *decl = dvi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + // If we are not a top level use, we must be a rc-identical transitive + // use. In such a case, we just print out the rc identical value + // without a projection path. This is because we now have a better + // name and the name is rc-identical to whatever was at the end of the + // projection path but is not at the end of that projection path. + printNote(stream, decl, + use->get() == value /*print projection path*/); } + resultingInferredDecls.emplace_back( + OptRemark::ArgumentKey{keyKind, "InferredValue"}, std::move(msg), + decl); + foundDeclFromUse = true; + return; } - } - // At this point, we could not infer any argument. See if we can look - // through loads. - // - // TODO: Add GEPs to construct a ProjectionPath. + // If we did not have a decl, see if we were asked for testing + // purposes to use SILDebugInfo to create a placeholder inferred + // value. + if (!DecllessDebugValueUseSILDebugInfo) + return; + + auto varInfo = dvi->getVarInfo(); + if (!varInfo) + return; + + auto name = varInfo->Name; + if (name.empty()) + return; + + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, name, use->get() == value /*print projection path*/); + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), dvi->getLoc())); + foundDeclFromUse = true; + }); - // Finally, see if we can look through a load... + // At this point, we could not infer any argument. See if we can look up the + // def-use graph and come up with a good location after looking through + // loads and projections. if (auto *li = dyn_cast(value)) { value = stripAccessMarkers(li->getOperand()); continue; @@ -305,7 +379,8 @@ bool ValueToDeclInferrer::infer( // TODO: We could emit at this point a msg for temporary allocations. // If we reached this point, we finished falling through the loop and return - // true. + // if we found any decls from uses. We always process everything so we /can/ + // potentially emit multiple diagnostics. return foundDeclFromUse; } } diff --git a/test/SILOptimizer/opt-remark-generator.sil b/test/SILOptimizer/opt-remark-generator.sil index 168aee0985fa5..f7bf9b681ba8e 100644 --- a/test/SILOptimizer/opt-remark-generator.sil +++ b/test/SILOptimizer/opt-remark-generator.sil @@ -4,51 +4,83 @@ sil_stage canonical import Builtin -sil @foo : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { -bb0(%0 : $Builtin.NativeObject): - debug_value %0 : $Builtin.NativeObject, let, name "arg" - strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} - // expected-note @-2 {{of 'arg'}} - retain_value %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} - // expected-note @-4 {{of 'arg'}} - strong_release %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} - // expected-note @-6 {{of 'arg'}} - release_value %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} - // expected-note @-8 {{of 'arg'}} - %9999 = tuple() - return %9999 : $() -} +////////////////// +// Declarations // +////////////////// -public enum TrivialState { +class Klass {} + +enum TrivialState { case first case second case third } struct StructWithOwner { - var owner: Builtin.NativeObject + var owner: Klass + var state: TrivialState +} + +struct KlassPair { + var lhs: Klass + var rhs: Klass +} + +struct StructWithOwnerAndState { + var structWithOwner: StructWithOwner var state: TrivialState } -sil @extract_out_singleobj_struct_subfield_1 : $@convention(thin) (@guaranteed StructWithOwner) -> Builtin.NativeObject { +/////////// +// Tests // +/////////// + +sil @simple : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { +bb0(%0 : $Builtin.NativeObject): + debug_value %0 : $Builtin.NativeObject, let, name "arg" + strong_retain %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-2 {{of 'arg'}} + retain_value %0 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + // expected-note @-4 {{of 'arg'}} + strong_release %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} + // expected-note @-6 {{of 'arg'}} + release_value %0 : $Builtin.NativeObject // expected-remark {{release of type 'Builtin.NativeObject'}} + // expected-note @-8 {{of 'arg'}} + %9999 = tuple() + return %9999 : $() +} + +sil @extract_out_singleobj_struct_subfield_1 : $@convention(thin) (@guaranteed StructWithOwner) -> Klass { bb0(%0 : $StructWithOwner): debug_value %0 : $StructWithOwner, let, name "x" %1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner - strong_retain %1 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} + strong_retain %1 : $Klass // expected-remark {{retain of type 'Klass'}} // expected-note @-3 {{of 'x.owner'}} - return %1 : $Builtin.NativeObject + return %1 : $Klass } // This case should never actually happen like this, but we should handle it in // a sane way by printing both notes for y and x and also make sure that we do // not infer .owner on y since y is on owner itself. -sil @extract_out_singleobj_struct_subfield_multiple_debugvalue : $@convention(thin) (@guaranteed StructWithOwner) -> Builtin.NativeObject { +sil @extract_out_singleobj_struct_subfield_multiple_debugvalue : $@convention(thin) (@guaranteed StructWithOwner) -> Klass { bb0(%0 : $StructWithOwner): debug_value %0 : $StructWithOwner, let, name "x" %1 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner - debug_value %1 : $Builtin.NativeObject, let, name "y" - strong_retain %1 : $Builtin.NativeObject // expected-remark {{retain of type 'Builtin.NativeObject'}} - // expected-note @-4 {{of 'x.owner'}} - // expected-note @-3 {{of 'y'}} - return %1 : $Builtin.NativeObject + debug_value %1 : $Klass, let, name "y" + strong_retain %1 : $Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-4 {{of 'x.owner'}} + // expected-note @-3 {{of 'y'}} + return %1 : $Klass +} + +// In this case, we emit the remark for x since its operand %2 is rc-identical +// to %0 the value we found while traversing our access path. +sil @rcidentity_based_use : $@convention(thin) (@guaranteed StructWithOwner, TrivialState) -> @owned Klass { +bb0(%0 : $StructWithOwner, %1 : $TrivialState): + %2 = struct $StructWithOwnerAndState(%0 : $StructWithOwner, %1 : $TrivialState) + debug_value %2 : $StructWithOwnerAndState, let, name "x" + %3 = struct_extract %0 : $StructWithOwner, #StructWithOwner.owner + strong_retain %3 : $Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-3 {{of 'x'}} + return %3 : $Klass } From bf7c03b1f6cce062e27684abe5018a723a594662 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 2 Sep 2020 10:14:51 -0700 Subject: [PATCH 513/663] Support cross compile Xcode toolchain for Apple Silicon Support cross compile Xcode toolchain for Apple Silicon * Add CMake flag DCMAKE_OSX_ARCHITECTURES to LLVM * Add CMake flag DCMAKE_OSX_ARCHITECTURES to cmark * Add CMake flag DCMAKE_OSX_ARCHITECTURES to lldb * Add CMake flag DCMAKE_OSX_ARCHITECTURES to llbuild * Add llbuild CMake options array to provide DCMAKE_OSX_ARCHITECTURES * [Build System] Use one install package for cross compile hosts * Remove Lipo before non-build-script-impl products * Add support to only lipo without running installable package tests * [Build System] Support cross compile install prefix for SwiftPM product in Swift Build Support * Use cross compile toolchain path for indexstoredb and swift-driver * Use cross compile toolchain path for swiftpm, swiftsyntax, swiftformat, and skstresstester * Add cross compile toolchain support to Benchmarks, and fix the python lint issue in skstresstester.py * [SwiftPM] Add support for cross-compile-hosts flag to build swiftpm using bootstrap script --- utils/build-presets.ini | 3 +++ utils/build-script | 10 +++++-- utils/build-script-impl | 24 ++++++++++------- .../products/benchmarks.py | 4 ++- .../products/indexstoredb.py | 7 ++++- .../swift_build_support/products/product.py | 9 +++++-- .../products/skstresstester.py | 15 ++++++----- .../products/swiftformat.py | 8 +++--- .../swift_build_support/products/swiftpm.py | 26 +++++++++++++++++-- .../products/swiftsyntax.py | 2 +- 10 files changed, 80 insertions(+), 28 deletions(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 6cfa2e6b749dc..18dba19e21e14 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1212,6 +1212,9 @@ compiler-vendor=apple dash-dash +# Cross compile for Apple Silicon +cross-compile-hosts=macosx-arm64 + lldb-no-debugserver lldb-use-system-debugserver lldb-build-type=Release diff --git a/utils/build-script b/utils/build-script index 10ee8f7efd235..18bbe73b1d4c3 100755 --- a/utils/build-script +++ b/utils/build-script @@ -942,8 +942,8 @@ class BuildScriptInvocation(object): for product_class in impl_product_classes: self._execute_install_action(host_target, product_class) - # Lipo... - self._execute_merged_host_lipo_action() + # Core Lipo... + self._execute_merged_host_lipo_core_action() # Non-build-script-impl products... # Note: currently only supports building for the host. @@ -987,6 +987,9 @@ class BuildScriptInvocation(object): for host_target in all_hosts: self._execute_package_action(host_target) + # Lipo... + self._execute_merged_host_lipo_action() + def _execute_build_action(self, host_target, product_class): action_name = "{}-{}-build".format(host_target.name, product_class.product_name()) @@ -1013,6 +1016,9 @@ class BuildScriptInvocation(object): def _execute_merged_host_lipo_action(self): self._execute_action("merged-hosts-lipo") + def _execute_merged_host_lipo_core_action(self): + self._execute_action("merged-hosts-lipo-core") + def _execute_action(self, action_name): shell.call_without_sleeping( [BUILD_SCRIPT_IMPL_PATH] + self.impl_args + diff --git a/utils/build-script-impl b/utils/build-script-impl index bced37215db7b..6d5ebb8e9a7bb 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -425,6 +425,7 @@ function set_build_options_for_host() { swift_cmake_options=() cmark_cmake_options=() lldb_cmake_options=() + llbuild_cmake_options=() SWIFT_HOST_VARIANT= SWIFT_HOST_VARIANT_SDK= SWIFT_HOST_VARIANT_ARCH= @@ -646,6 +647,7 @@ function set_build_options_for_host() { -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})" -DCMAKE_OSX_SYSROOT:PATH="${cmake_os_sysroot}" -DCMAKE_OSX_DEPLOYMENT_TARGET="${cmake_osx_deployment_target}" + -DCMAKE_OSX_ARCHITECTURES="${architecture}" ) llvm_cmake_options=( -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING="${cmake_osx_deployment_target}" @@ -655,6 +657,7 @@ function set_build_options_for_host() { -DCOMPILER_RT_ENABLE_TVOS:BOOL=FALSE -DSANITIZER_MIN_OSX_VERSION="${cmake_osx_deployment_target}" -DLLVM_ENABLE_MODULES:BOOL="$(true_false ${LLVM_ENABLE_MODULES})" + -DCMAKE_OSX_ARCHITECTURES="${architecture}" ) if [[ $(is_llvm_lto_enabled) == "TRUE" ]]; then llvm_cmake_options+=( @@ -686,6 +689,10 @@ function set_build_options_for_host() { lldb_cmake_options+=( -DCMAKE_OSX_SYSROOT:PATH="${cmake_os_sysroot}" + -DCMAKE_OSX_ARCHITECTURES="${architecture}" + ) + llbuild_cmake_options+=( + -DCMAKE_OSX_ARCHITECTURES="${architecture}" ) ;; esac @@ -2025,6 +2032,7 @@ for host in "${ALL_HOSTS[@]}"; do llbuild) cmake_options=( "${cmake_options[@]}" + "${llbuild_cmake_options[@]}" -DCMAKE_BUILD_TYPE:STRING="${LLBUILD_BUILD_TYPE}" -DCMAKE_C_COMPILER:PATH="${CLANG_BIN}/clang" @@ -3031,11 +3039,7 @@ function build_and_test_installable_package() { local host_install_destdir="$(get_host_install_destdir ${host})" local host_install_prefix="$(get_host_install_prefix ${host})" - if [[ $(has_cross_compile_hosts) ]]; then - package_for_host="${INSTALLABLE_PACKAGE}-${host}" - else - package_for_host="${INSTALLABLE_PACKAGE}" - fi + package_for_host="${INSTALLABLE_PACKAGE}" echo "--- Creating installable package ---" echo "-- Package file: ${package_for_host} --" @@ -3110,7 +3114,7 @@ function build_and_test_installable_package() { PKG_TESTS_SANDBOX_PARENT="$(build_directory swift_package_sandbox_${host} none)" PKG_TESTS_TEMPS="${PKG_TESTS_SANDBOX_PARENT}"/"tests" - if [[ "${host}" == "macosx-"* ]] ; then + if [[ "${host}" == "macosx-"* ]] || [[ "${host}" == "merged-hosts" ]]; then PKG_TESTS_SANDBOX="${PKG_TESTS_SANDBOX_PARENT}"/"${TOOLCHAIN_PREFIX}" else # Linux PKG_TESTS_SANDBOX="${PKG_TESTS_SANDBOX_PARENT}" @@ -3151,7 +3155,7 @@ if [[ ${#LIPO_SRC_DIRS[@]} -gt 0 ]]; then # This is from multiple hosts; Which host should we say it is? # Let's call it 'merged-hosts' so that we can identify it. - if [[ $(should_execute_action "${mergedHost}-lipo") ]]; then + if [[ $(should_execute_action "${mergedHost}-lipo") || $(should_execute_action "${mergedHost}-lipo-core") ]]; then # Allow passing lipo with --host-lipo if [[ -z "${HOST_LIPO}" ]] ; then LIPO_PATH=$(xcrun_find_tool lipo) @@ -3160,8 +3164,10 @@ if [[ ${#LIPO_SRC_DIRS[@]} -gt 0 ]]; then fi call "${SWIFT_SOURCE_DIR}"/utils/recursive-lipo --lipo=${LIPO_PATH} --copy-subdirs="$(get_host_install_prefix ${host})lib/swift $(get_host_install_prefix ${host})lib/swift_static" --destination="$(get_host_install_destdir ${mergedHost})" ${LIPO_SRC_DIRS[@]} - # Build and test the lipo-ed package. - build_and_test_installable_package ${mergedHost} + if [[ $(should_execute_action "${mergedHost}-lipo") ]]; then + # Build and test the lipo-ed package. + build_and_test_installable_package ${mergedHost} + fi fi fi # END diff --git a/utils/swift_build_support/swift_build_support/products/benchmarks.py b/utils/swift_build_support/swift_build_support/products/benchmarks.py index cac1e241e4451..b7a14ecc658fa 100644 --- a/utils/swift_build_support/swift_build_support/products/benchmarks.py +++ b/utils/swift_build_support/swift_build_support/products/benchmarks.py @@ -82,7 +82,9 @@ def get_dependencies(cls): def run_build_script_helper(host_target, product, args): - toolchain_path = args.install_destdir + toolchain_path = swiftpm.SwiftPM.get_install_destdir(args, + host_target, + product.build_dir) if platform.system() == 'Darwin': # The prefix is an absolute path, so concatenate without os.path. toolchain_path += \ diff --git a/utils/swift_build_support/swift_build_support/products/indexstoredb.py b/utils/swift_build_support/swift_build_support/products/indexstoredb.py index 65d720c4889fa..83b4ac91811c4 100644 --- a/utils/swift_build_support/swift_build_support/products/indexstoredb.py +++ b/utils/swift_build_support/swift_build_support/products/indexstoredb.py @@ -76,7 +76,12 @@ def run_build_script_helper(action, host_target, product, args, script_path = os.path.join( product.source_dir, 'Utilities', 'build-script-helper.py') - toolchain_path = targets.toolchain_path(args.install_destdir, + install_destdir = args.install_destdir + if swiftpm.SwiftPM.has_cross_compile_hosts(args): + install_destdir = swiftpm.SwiftPM.get_install_destdir(args, + host_target, + product.build_dir) + toolchain_path = targets.toolchain_path(install_destdir, args.install_prefix) is_release = product.is_release() configuration = 'release' if is_release else 'debug' diff --git a/utils/swift_build_support/swift_build_support/products/product.py b/utils/swift_build_support/swift_build_support/products/product.py index 5ccfa48283e88..ba6f673bb6c99 100644 --- a/utils/swift_build_support/swift_build_support/products/product.py +++ b/utils/swift_build_support/swift_build_support/products/product.py @@ -11,6 +11,7 @@ # ---------------------------------------------------------------------------- import abc +import os from .. import cmake from .. import targets @@ -162,13 +163,17 @@ def is_release(self): """ return is_release_variant(self.args.build_variant) - def install_toolchain_path(self): + def install_toolchain_path(self, host_target): """toolchain_path() -> string Returns the path to the toolchain that is being created as part of this build. """ - return targets.toolchain_path(self.args.install_destdir, + install_destdir = self.args.install_destdir + if self.args.cross_compile_hosts: + build_root = os.path.dirname(self.build_dir) + install_destdir = '%s/intermediate-install/%s' % (build_root, host_target) + return targets.toolchain_path(install_destdir, self.args.install_prefix) diff --git a/utils/swift_build_support/swift_build_support/products/skstresstester.py b/utils/swift_build_support/swift_build_support/products/skstresstester.py index ae79373d99c7c..0656a2bfd7d3a 100644 --- a/utils/swift_build_support/swift_build_support/products/skstresstester.py +++ b/utils/swift_build_support/swift_build_support/products/skstresstester.py @@ -50,7 +50,7 @@ def is_swiftpm_unified_build_product(cls): def package_name(self): return 'SourceKitStressTester' - def run_build_script_helper(self, action, additional_params=[]): + def run_build_script_helper(self, action, host_target, additional_params=[]): script_path = os.path.join( self.source_dir, 'build-script-helper.py') @@ -60,7 +60,7 @@ def run_build_script_helper(self, action, additional_params=[]): script_path, action, '--package-dir', self.package_name(), - '--toolchain', self.install_toolchain_path(), + '--toolchain', self.install_toolchain_path(host_target), '--config', configuration, '--build-dir', self.build_dir, '--multiroot-data-file', MULTIROOT_DATA_FILE_PATH, @@ -84,20 +84,23 @@ def build(self, host_target): "than Darwin".format( product=self.package_name())) - self.run_build_script_helper('build') + self.run_build_script_helper('build', host_target) def should_test(self, host_target): return self.args.test_skstresstester def test(self, host_target): - self.run_build_script_helper('test') + self.run_build_script_helper('test', host_target) def should_install(self, host_target): return self.args.install_skstresstester def install(self, host_target): - install_prefix = self.args.install_destdir + self.args.install_prefix - self.run_build_script_helper('install', [ + install_destdir = swiftpm.SwiftPM.get_install_destdir(self.args, + host_target, + self.build_dir) + install_prefix = install_destdir + self.args.install_prefix + self.run_build_script_helper('install', host_target, [ '--prefix', install_prefix ]) diff --git a/utils/swift_build_support/swift_build_support/products/swiftformat.py b/utils/swift_build_support/swift_build_support/products/swiftformat.py index ae6323cddadf8..940ccd1043e6c 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftformat.py +++ b/utils/swift_build_support/swift_build_support/products/swiftformat.py @@ -46,7 +46,7 @@ def is_build_script_impl_product(cls): def is_swiftpm_unified_build_product(cls): return True - def run_build_script_helper(self, action, additional_params=[]): + def run_build_script_helper(self, action, host_target, additional_params=[]): script_path = os.path.join( self.source_dir, 'build-script-helper.py') @@ -55,7 +55,7 @@ def run_build_script_helper(self, action, additional_params=[]): helper_cmd = [ script_path, action, - '--toolchain', self.install_toolchain_path(), + '--toolchain', self.install_toolchain_path(host_target), '--configuration', configuration, '--build-path', self.build_dir, '--multiroot-data-file', MULTIROOT_DATA_FILE_PATH, @@ -74,13 +74,13 @@ def should_build(self, host_target): return True def build(self, host_target): - self.run_build_script_helper('build') + self.run_build_script_helper('build', host_target) def should_test(self, host_target): return self.args.test_swiftformat def test(self, host_target): - self.run_build_script_helper('test') + self.run_build_script_helper('test', host_target) def should_install(self, host_target): return False diff --git a/utils/swift_build_support/swift_build_support/products/swiftpm.py b/utils/swift_build_support/swift_build_support/products/swiftpm.py index 412dc52814f5c..25e982e23f173 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftpm.py +++ b/utils/swift_build_support/swift_build_support/products/swiftpm.py @@ -40,7 +40,7 @@ def should_build(self, host_target): def run_bootstrap_script(self, action, host_target, additional_params=[]): script_path = os.path.join( self.source_dir, 'Utilities', 'bootstrap') - toolchain_path = self.install_toolchain_path() + toolchain_path = self.install_toolchain_path(host_target) swiftc = os.path.join(toolchain_path, "bin", "swiftc") # FIXME: We require llbuild build directory in order to build. Is @@ -86,6 +86,12 @@ def run_bootstrap_script(self, action, host_target, additional_params=[]): "--foundation-build-dir", foundation_build_dir ] + # Pass Cross compile host info + if self.has_cross_compile_hosts(self.args): + helper_cmd += ['--cross-compile-hosts'] + for cross_compile_host in self.args.cross_compile_hosts: + helper_cmd += [cross_compile_host] + helper_cmd.extend(additional_params) shell.call(helper_cmd) @@ -108,8 +114,24 @@ def clean(self, host_target): def should_install(self, host_target): return self.args.install_swiftpm + @classmethod + def has_cross_compile_hosts(self, args): + return args.cross_compile_hosts + + @classmethod + def get_install_destdir(self, args, host_target, build_dir): + install_destdir = args.install_destdir + if self.has_cross_compile_hosts(args): + build_root = os.path.dirname(build_dir) + install_destdir = '%s/intermediate-install/%s' % (build_root, host_target) + return install_destdir + def install(self, host_target): - install_prefix = self.args.install_destdir + self.args.install_prefix + install_destdir = self.get_install_destdir(self.args, + host_target, + self.build_dir) + install_prefix = install_destdir + self.args.install_prefix + self.run_bootstrap_script('install', host_target, [ '--prefix', install_prefix ]) diff --git a/utils/swift_build_support/swift_build_support/products/swiftsyntax.py b/utils/swift_build_support/swift_build_support/products/swiftsyntax.py index 9dd6a8436b30f..00cdef0dd0c5c 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftsyntax.py +++ b/utils/swift_build_support/swift_build_support/products/swiftsyntax.py @@ -55,7 +55,7 @@ def run_swiftsyntax_build_script(self, target, additional_params=[]): script_path, '--build-dir', self.build_dir, '--multiroot-data-file', MULTIROOT_DATA_FILE_PATH, - '--toolchain', self.install_toolchain_path(), + '--toolchain', self.install_toolchain_path(target), '--filecheck-exec', os.path.join(llvm_build_dir, 'bin', 'FileCheck'), ] From dadf2b47cc7e2e064649ad478d155494c64556d7 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 2 Sep 2020 11:03:21 -0700 Subject: [PATCH 514/663] [ConstraintSystem] Track invalid function builder bodies to avoid duplicate diagnostics --- lib/Sema/BuilderTransform.cpp | 9 +++++++++ lib/Sema/ConstraintSystem.h | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index c1a81fcf8a676..acb8d8881c658 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1655,6 +1655,13 @@ ConstraintSystem::matchFunctionBuilder( assert(builder && "Bad function builder type"); assert(builder->getAttrs().hasAttribute()); + if (InvalidFunctionBuilderBodies.count(fn)) { + (void)recordFix( + IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration( + *this, getConstraintLocator(fn.getBody()))); + return getTypeMatchSuccess(); + } + // Pre-check the body: pre-check any expressions in it and look // for return statements. auto request = @@ -1720,6 +1727,8 @@ ConstraintSystem::matchFunctionBuilder( return getTypeMatchFailure(locator); if (transaction.hasErrors()) { + InvalidFunctionBuilderBodies.insert(fn); + if (recordFix( IgnoreInvalidFunctionBuilderBody::duringConstraintGeneration( *this, getConstraintLocator(fn.getBody())))) diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 18579bfc857a8..e2a8ea09fde35 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -2025,6 +2025,13 @@ class ConstraintSystem { /// from declared parameters/result and body. llvm::MapVector ClosureTypes; + /// This is a *global* list of all function builder bodies that have + /// been determined to be incorrect by failing constraint generation. + /// + /// Tracking this information is useful to avoid producing duplicate + /// diagnostics when function builder has multiple overloads. + llvm::SmallDenseSet InvalidFunctionBuilderBodies; + /// Maps node types used within all portions of the constraint /// system, instead of directly using the types on the /// nodes themselves. This allows us to typecheck and From d2f5e63773b0189e3f07621249c224f9266e20e1 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 2 Sep 2020 11:16:18 -0700 Subject: [PATCH 515/663] [TypeChecker] NFC: Add test-case for rdar://problem/65983237 --- test/Constraints/function_builder_diags.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 89e4264df312f..36bba5457d066 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -619,6 +619,14 @@ struct MyView { } // expected-error {{expected identifier after '.' expression}} } + @TupleBuilder var invalidCaseWithoutDot: some P { + switch Optional.some(1) { + case none: 42 // expected-error {{cannot find 'none' in scope}} + case .some(let x): + 0 + } + } + @TupleBuilder var invalidConversion: Int { // expected-error {{cannot convert value of type 'String' to specified type 'Int'}} "" } From aa48494c7480a37e075ed59f9476301dfcf20022 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 2 Sep 2020 12:47:37 -0700 Subject: [PATCH 516/663] [Serialization] Local allocate ModuleFileSharedCore.ModuleInterfacePath 'ModuleInterfacePath' is passed as 'StringRef' that memory used to reside in ASTContext. But 'ModuleFileSharedCore' should be 'ASTContext' independent. So copy it using its own allocator. --- lib/Serialization/ModuleFileSharedCore.h | 7 +++++-- lib/Serialization/SerializedModuleLoader.cpp | 4 +--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index f7be1d18b9746..5991b92a108ed 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -461,8 +461,11 @@ class ModuleFileSharedCore { auto *core = new ModuleFileSharedCore( std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), std::move(moduleSourceInfoInputBuffer), isFramework, info, extInfo); - if (!moduleInterfacePath.empty()) - core->ModuleInterfacePath = moduleInterfacePath; + if (!moduleInterfacePath.empty()) { + ArrayRef path; + core->allocateBuffer(path, moduleInterfacePath); + core->ModuleInterfacePath = StringRef(path.data(), path.size()); + } theModule.reset(core); return info; } diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index a82ee47568e5a..63b9199bdb418 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -990,10 +990,8 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, Ctx.addLoadedModule(M); SWIFT_DEFER { M->setHasResolvedImports(); }; - StringRef moduleInterfacePathStr = - Ctx.AllocateCopy(moduleInterfacePath.str()); auto *file = - loadAST(*M, moduleID.Loc, moduleInterfacePathStr, + loadAST(*M, moduleID.Loc, moduleInterfacePath, std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), std::move(moduleSourceInfoInputBuffer), isFramework); if (file) { From bfc9b5447f4499bfb363b948b91524ad6e5759a7 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Wed, 2 Sep 2020 13:49:01 -0700 Subject: [PATCH 517/663] Add llvm-nm to list of LLVM tools built with stdlib standalone mode (#33681) --- utils/build-script-impl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 6d5ebb8e9a7bb..7cca9f519c4d7 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1557,13 +1557,14 @@ for host in "${ALL_HOSTS[@]}"; do # build of Swift depend on these for building and testing. build_targets=(llvm-tblgen clang-resource-headers intrinsics_gen clang-tablegen-targets) # If we are not performing a toolchain only build, then we - # also want to include FileCheck and not for testing + # also want to include FileCheck, not, llvm-nm for testing # purposes. if [[ ! "${BUILD_TOOLCHAIN_ONLY}" ]] ; then build_targets=( "${build_targets[@]}" FileCheck not + llvm-nm ) fi fi From ac6dffdf411d8522612a56f0102b54f3e2b97258 Mon Sep 17 00:00:00 2001 From: Julian Lettner Date: Wed, 2 Sep 2020 15:03:28 -0700 Subject: [PATCH 518/663] [Sanitizer] Disable inlining to improve robustness of test (#33753) This test checks that Sanitizer reports contain properly symbolicated stacks. Let's make sure that all of the expected frames appear in the stack by disabling inlining and preventing tail call optimization. rdar://68171463 Co-authored-by: Julian Lettner --- test/Sanitizers/symbolication-linux.swift | 8 +++++--- test/Sanitizers/symbolication.swift | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/Sanitizers/symbolication-linux.swift b/test/Sanitizers/symbolication-linux.swift index 8e1827aa737c7..a892bc88d2cd9 100644 --- a/test/Sanitizers/symbolication-linux.swift +++ b/test/Sanitizers/symbolication-linux.swift @@ -11,23 +11,25 @@ // symbolication. Note that `llvm-symbolizer` does not demangle Swift symbol // names, so we use `swift demangle`. +@inline(never) func foo() { let x = UnsafeMutablePointer.allocate(capacity: 1) x.deallocate() print(x.pointee) } +@inline(never) func bar() { foo() + print("Prevent tail call optimization") } bar() - // Out-of-process -// OOP: #0 0x{{[0-9a-f]+}} in main.foo() -> () {{.*}}symbolication-linux.swift:[[@LINE-11]] +// OOP: #0 0x{{[0-9a-f]+}} in main.foo() -> () {{.*}}symbolication-linux.swift:[[@LINE-12]] // OOP-NEXT: #1 0x{{[0-9a-f]+}} in main.bar() -> () {{.*}}symbolication-linux.swift:[[@LINE-8]] -// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main {{.*}}symbolication-linux.swift:[[@LINE-6]] +// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main {{.*}}symbolication-linux.swift:[[@LINE-5]] // In-process // IP: #0 0x{{[0-9a-f]+}} in main.foo() -> ()+0x diff --git a/test/Sanitizers/symbolication.swift b/test/Sanitizers/symbolication.swift index 9f95a4f8c033a..89f3335cfd6c2 100644 --- a/test/Sanitizers/symbolication.swift +++ b/test/Sanitizers/symbolication.swift @@ -9,23 +9,25 @@ // both out-of-process (via `atos`) and when falling back to in-process // symbolication. Note that `atos` also demangles Swift symbol names. +@inline(never) func foo() { let x = UnsafeMutablePointer.allocate(capacity: 1) x.deallocate() print(x.pointee) } +@inline(never) func bar() { foo() + print("Prevent tail call optimization") } bar() - // Out-of-process -// OOP: #0 0x{{[0-9a-f]+}} in foo() symbolication.swift:[[@LINE-11]] +// OOP: #0 0x{{[0-9a-f]+}} in foo() symbolication.swift:[[@LINE-12]] // OOP-NEXT: #1 0x{{[0-9a-f]+}} in bar() symbolication.swift:[[@LINE-8]] -// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main symbolication.swift:[[@LINE-6]] +// OOP-NEXT: #2 0x{{[0-9a-f]+}} in main symbolication.swift:[[@LINE-5]] // In-process // IP: #0 0x{{[0-9a-f]+}} in main.foo() -> ()+0x From 7462c83a2a66552cb285322025cd1e8899f2d610 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Wed, 2 Sep 2020 09:49:35 -0700 Subject: [PATCH 519/663] Change `getAdjointBuffer` to return `SILValue` instead of `SILValue &`. Fixes a use-after-free crash. --- .../Differentiation/PullbackCloner.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 7d0c30644f9e0..f1c1fca4431f7 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -562,7 +562,7 @@ class PullbackCloner::Implementation final /// /// This method first tries to find an existing entry in the adjoint buffer /// mapping. If no entry exists, creates a zero adjoint buffer. - SILValue &getAdjointBuffer(SILBasicBlock *origBB, SILValue originalValue) { + SILValue getAdjointBuffer(SILBasicBlock *origBB, SILValue originalValue) { assert(getTangentValueCategory(originalValue) == SILValueCategory::Address); assert(originalValue->getFunction() == &getOriginal()); auto insertion = bufferMap.try_emplace({origBB, originalValue}, SILValue()); @@ -1470,7 +1470,7 @@ class PullbackCloner::Implementation final /// Adjoint: adj[x] += load adj[y]; adj[y] = 0 void visitStoreOperation(SILBasicBlock *bb, SILLocation loc, SILValue origSrc, SILValue origDest) { - auto &adjBuf = getAdjointBuffer(bb, origDest); + auto adjBuf = getAdjointBuffer(bb, origDest); switch (getTangentValueCategory(origSrc)) { case SILValueCategory::Object: { auto adjVal = builder.emitLoadValueOperation( @@ -1502,7 +1502,7 @@ class PullbackCloner::Implementation final /// Adjoint: adj[x] += adj[y]; adj[y] = 0 void visitCopyAddrInst(CopyAddrInst *cai) { auto *bb = cai->getParent(); - auto &adjDest = getAdjointBuffer(bb, cai->getDest()); + auto adjDest = getAdjointBuffer(bb, cai->getDest()); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, cai->getSrc(), adjDest, cai->getLoc()); builder.emitDestroyAddrAndFold(cai->getLoc(), adjDest); @@ -1521,7 +1521,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, cvi); + auto adjDest = getAdjointBuffer(bb, cvi); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, cvi->getOperand(), adjDest, cvi->getLoc()); builder.emitDestroyAddrAndFold(cvi->getLoc(), adjDest); @@ -1543,7 +1543,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, bbi); + auto adjDest = getAdjointBuffer(bb, bbi); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, bbi->getOperand(), adjDest, bbi->getLoc()); builder.emitDestroyAddrAndFold(bbi->getLoc(), adjDest); @@ -1582,8 +1582,8 @@ class PullbackCloner::Implementation final void visitUnconditionalCheckedCastAddrInst( UnconditionalCheckedCastAddrInst *uccai) { auto *bb = uccai->getParent(); - auto &adjDest = getAdjointBuffer(bb, uccai->getDest()); - auto &adjSrc = getAdjointBuffer(bb, uccai->getSrc()); + auto adjDest = getAdjointBuffer(bb, uccai->getDest()); + auto adjSrc = getAdjointBuffer(bb, uccai->getSrc()); auto destType = remapType(adjDest->getType()); auto castBuf = builder.createAllocStack(uccai->getLoc(), adjSrc->getType()); builder.createUnconditionalCheckedCastAddr( @@ -1612,7 +1612,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, urci); + auto adjDest = getAdjointBuffer(bb, urci); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, urci->getOperand(), adjDest, urci->getLoc()); builder.emitDestroyAddrAndFold(urci->getLoc(), adjDest); @@ -1639,7 +1639,7 @@ class PullbackCloner::Implementation final break; } case SILValueCategory::Address: { - auto &adjDest = getAdjointBuffer(bb, ui); + auto adjDest = getAdjointBuffer(bb, ui); auto destType = remapType(adjDest->getType()); addToAdjointBuffer(bb, ui->getOperand(), adjDest, ui->getLoc()); builder.emitDestroyAddrAndFold(ui->getLoc(), adjDest); From a4d731ed9f6fb354ab9336f497c22c7ac1517823 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 2 Sep 2020 09:34:35 -0700 Subject: [PATCH 520/663] ModuleLoader: remove several walk-arounds for not having a persistent ClangImporterOptions available. NFC --- include/swift/ClangImporter/ClangImporter.h | 1 - .../swift/Frontend/ModuleInterfaceLoader.h | 3 +- lib/ClangImporter/ClangImporter.cpp | 5 -- lib/ClangImporter/ImporterImpl.h | 2 - lib/Frontend/Frontend.cpp | 2 +- lib/Frontend/ModuleInterfaceLoader.cpp | 51 +++++++------------ lib/FrontendTool/ScanDependencies.cpp | 4 +- .../swift-api-digester/swift-api-digester.cpp | 5 +- 8 files changed, 24 insertions(+), 49 deletions(-) diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 9efa52313e112..42896fd21b190 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -472,7 +472,6 @@ class ClangImporter final : public ClangModuleLoader { bool isSerializable(const clang::Type *type, bool checkCanonical) const override; - ArrayRef getExtraClangArgs() const; }; ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN, diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 787829882c82b..9996d8e20d8d4 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -420,8 +420,8 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate { DiagnosticEngine &Diags, const SearchPathOptions &searchPathOpts, const LangOptions &langOpts, + const ClangImporterOptions &clangImporterOpts, ModuleInterfaceLoaderOptions LoaderOpts, - ClangModuleLoader *clangImporter, bool buildModuleCacheDirIfAbsent, StringRef moduleCachePath, StringRef prebuiltCachePath, @@ -448,7 +448,6 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate { llvm::SmallString<256> &OutPath, StringRef &CacheHash); std::string getCacheHash(StringRef useInterfacePath); - void addExtraClangArg(StringRef Arg); }; } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index da5b09347ef9c..49b1afda933ec 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -969,10 +969,6 @@ ClangImporter::createClangInvocation(ClangImporter *importer, nullptr, false, CC1Args); } -ArrayRef ClangImporter::getExtraClangArgs() const { - return Impl.ExtraClangArgs; -} - std::unique_ptr ClangImporter::create(ASTContext &ctx, std::string swiftPCHHash, DependencyTracker *tracker, @@ -982,7 +978,6 @@ ClangImporter::create(ASTContext &ctx, auto &importerOpts = ctx.ClangImporterOpts; importer->Impl.ClangArgs = getClangArguments(ctx); ArrayRef invocationArgStrs = importer->Impl.ClangArgs; - importer->Impl.ExtraClangArgs = importerOpts.ExtraArgs; if (importerOpts.DumpClangDiagnostics) { llvm::errs() << "'"; llvm::interleave( diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index e5e1598e2cffb..79ddfb0938b5f 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -393,8 +393,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// Clang arguments used to create the Clang invocation. std::vector ClangArgs; - /// Extra clang args specified via "-Xcc" - std::vector ExtraClangArgs; public: /// Mapping of already-imported declarations. llvm::DenseMap, Decl *> ImportedDecls; diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 55999795522b8..5efc9c5571e43 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -538,8 +538,8 @@ bool CompilerInstance::setUpModuleLoaders() { ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); InterfaceSubContextDelegateImpl ASTDelegate(Context->SourceMgr, Context->Diags, Context->SearchPathOpts, Context->LangOpts, + Context->ClangImporterOpts, LoaderOpts, - Context->getClangModuleLoader(), /*buildModuleCacheDirIfAbsent*/false, ModuleCachePath, FEOpts.PrebuiltModuleCachePath, diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 2029ff1de9dc1..fd911eba68572 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -844,8 +844,8 @@ class ModuleInterfaceLoaderImpl { } InterfaceSubContextDelegateImpl astDelegate(ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts, + ctx.ClangImporterOpts, Opts, - ctx.getClangModuleLoader(), /*buildModuleCacheDirIfAbsent*/true, cacheDir, prebuiltCacheDir, @@ -1084,20 +1084,12 @@ bool ModuleInterfaceLoader::buildSwiftModuleFromSwiftInterface( bool SerializeDependencyHashes, bool TrackSystemDependencies, ModuleInterfaceLoaderOptions LoaderOpts) { InterfaceSubContextDelegateImpl astDelegate(SourceMgr, Diags, - SearchPathOpts, LangOpts, + SearchPathOpts, LangOpts, ClangOpts, LoaderOpts, - /*clangImporter*/nullptr, /*CreateCacheDirIfAbsent*/true, CacheDir, PrebuiltCacheDir, SerializeDependencyHashes, TrackSystemDependencies); - // At this point we don't have an ClangImporter instance because the instance - // is created later when we create a new ASTContext to build the interface. - // Thus, we have to add these extra clang flags manually here to ensure explict - // module building works. - for (auto &Arg: ClangOpts.ExtraArgs) { - astDelegate.addExtraClangArg(Arg); - } ModuleInterfaceBuilder builder(SourceMgr, Diags, astDelegate, InPath, ModuleName, CacheDir, PrebuiltCacheDir, LoaderOpts.disableInterfaceLock); @@ -1238,19 +1230,13 @@ bool InterfaceSubContextDelegateImpl::extractSwiftInterfaceVersionAndArgs( return false; } -void InterfaceSubContextDelegateImpl::addExtraClangArg(StringRef arg) { - genericSubInvocation.getClangImporterOptions().ExtraArgs.push_back(arg); - GenericArgs.push_back("-Xcc"); - GenericArgs.push_back(ArgSaver.save(arg)); -} - InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( SourceManager &SM, DiagnosticEngine &Diags, const SearchPathOptions &searchPathOpts, const LangOptions &langOpts, + const ClangImporterOptions &clangImporterOpts, ModuleInterfaceLoaderOptions LoaderOpts, - ClangModuleLoader *clangImporter, bool buildModuleCacheDirIfAbsent, StringRef moduleCachePath, StringRef prebuiltCachePath, @@ -1288,22 +1274,21 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( StringRef explictSwiftModuleMap = searchPathOpts.ExplicitSwiftModuleMap; genericSubInvocation.getSearchPathOptions().ExplicitSwiftModuleMap = explictSwiftModuleMap; - if (clangImporter) { - // We need to add these extra clang flags because explict module building - // related flags are all there: -fno-implicit-modules, -fmodule-map-file=, - // and -fmodule-file=. - // If we don't add these flags, the interface will be built with implicit - // PCMs. - for (auto arg: static_cast(clangImporter)->getExtraClangArgs()) { - addExtraClangArg(arg); - } - // Respect the detailed-record preprocessor setting of the parent context. - // This, and the "raw" clang module format it implicitly enables, are - // required by sourcekitd. - auto &Opts = clangImporter->getClangInstance().getPreprocessorOpts(); - if (Opts.DetailedRecord) { - genericSubInvocation.getClangImporterOptions().DetailedPreprocessingRecord = true; - } + auto &subClangImporterOpts = genericSubInvocation.getClangImporterOptions(); + // Respect the detailed-record preprocessor setting of the parent context. + // This, and the "raw" clang module format it implicitly enables, are + // required by sourcekitd. + subClangImporterOpts.DetailedPreprocessingRecord = + clangImporterOpts.DetailedPreprocessingRecord; + // We need to add these extra clang flags because explict module building + // related flags are all there: -fno-implicit-modules, -fmodule-map-file=, + // and -fmodule-file=. + // If we don't add these flags, the interface will be built with implicit + // PCMs. + subClangImporterOpts.ExtraArgs = clangImporterOpts.ExtraArgs; + for (auto arg: subClangImporterOpts.ExtraArgs) { + GenericArgs.push_back("-Xcc"); + GenericArgs.push_back(ArgSaver.save(arg)); } // Tell the genericSubInvocation to serialize dependency hashes if asked to do so. diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 34e99395e1b17..3172db29098f4 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -641,8 +641,8 @@ static bool scanModuleDependencies(CompilerInstance &instance, ModuleDependenciesCache cache; InterfaceSubContextDelegateImpl ASTDelegate(ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts, + ctx.ClangImporterOpts, LoaderOpts, - ctx.getClangModuleLoader(), /*buildModuleCacheDirIfAbsent*/false, ModuleCachePath, FEOpts.PrebuiltModuleCachePath, @@ -839,8 +839,8 @@ bool swift::scanDependencies(CompilerInstance &instance) { ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); InterfaceSubContextDelegateImpl ASTDelegate(ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts, + ctx.ClangImporterOpts, LoaderOpts, - ctx.getClangModuleLoader(), /*buildModuleCacheDirIfAbsent*/false, ModuleCachePath, FEOpts.PrebuiltModuleCachePath, diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index 05ec2909a02fe..bfc336774bb59 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -2425,9 +2425,8 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, LeftCollector.deSerialize(LeftPath); SwiftDeclCollector RightCollector(Ctx); RightCollector.deSerialize(RightPath); - diagnoseModuleChange(Ctx, LeftCollector.getSDKRoot(), RightCollector.getSDKRoot(), - OutputPath, std::move(ProtocolReqAllowlist)); - return options::CompilerStyleDiags && Ctx.getDiags().hadAnyError() ? 1 : 0; + return diagnoseModuleChange(Ctx, LeftCollector.getSDKRoot(), + RightCollector.getSDKRoot(), OutputPath, std::move(ProtocolReqAllowlist)); } static void populateAliasChanges(NodeMap &AliasMap, DiffVector &AllItems, From ed7e03b21b93b67fdcdca3dee494d9f2f811eb47 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Wed, 2 Sep 2020 19:27:05 -0300 Subject: [PATCH 521/663] [CSDiagnostics] Ensure fix-it inserts uses correct location in infered key path root optional unwrapped --- lib/Sema/CSDiagnostics.cpp | 2 ++ test/expr/unary/keypath/keypath.swift | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index ed980fef21cb6..c85f8ceca0766 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1042,6 +1042,8 @@ SourceRange MemberAccessOnOptionalBaseFailure::getSourceRange() const { if (componentPathElt->getIndex() == 0) { if (auto rootType = keyPathExpr->getRootType()) { return rootType->getSourceRange(); + } else { + return keyPathExpr->getComponents().front().getLoc(); } } else { auto componentIdx = componentPathElt->getIndex() - 1; diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index 326e148b5b6a7..08282b4cd1bf2 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -1012,6 +1012,11 @@ func testMemberAccessOnOptionalKeyPathComponent() { let _ : KeyPath = \.count // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}} // expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{37-37=?.}} // expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{37-37=!.}} + + let _ : KeyPath = \.utf8.count + // expected-error@-1 {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'utf8' of unwrapped type 'String'}} + // expected-note@-2 {{chain the optional using '?.' to access unwrapped type member 'utf8'}} {{37-37=?.}} + // expected-note@-3 {{unwrap the optional using '!.' to access unwrapped type member 'utf8'}} {{37-37=!.}} } func testSyntaxErrors() { From 33bb4837dab5ca0397d52c0e302c3e97b3081773 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Wed, 2 Sep 2020 18:26:02 -0400 Subject: [PATCH 522/663] [test][IRGen] Loosen check in test unused.sil. In #33246 among other changes, a CHECK referring to the size of _swift1_autolink_entries was changed from a regex-based expectation to a static value. This means on platforms with different link flags, this expectation fails but does not signify any real failure. Revert back to using a regex check for the length of this constant. --- test/IRGen/unused.sil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/IRGen/unused.sil b/test/IRGen/unused.sil index e15b50531c5d1..8b0d06fb0e7a3 100644 --- a/test/IRGen/unused.sil +++ b/test/IRGen/unused.sil @@ -56,7 +56,7 @@ bb0(%0 : $Int32, %1 : $UnsafeMutablePointer> // CHECK-elf: @"\01l_entry_point" = private constant { i32 } { i32 trunc (i64 sub (i64 ptrtoint (i32 (i32, i8**)* @main to i64), i64 ptrtoint ({ i32 }* @"\01l_entry_point" to i64)) to i32) }, section "swift5_entry", align 4 // CHECK-macho: @llvm.used = appending global [4 x i8*] [i8* bitcast (void ()* @frieda to i8*), i8* bitcast (i32 (i32, i8**)* @main to i8*), i8* bitcast ({ i32 }* @"\01l_entry_point" to i8*), i8* bitcast (i16* @__swift_reflection_version to i8*)], section "llvm.metadata", align 8 -// CHECK-elf: @llvm.used = appending global [5 x i8*] [i8* bitcast (void ()* @frieda to i8*), i8* bitcast (i32 (i32, i8**)* @main to i8*), i8* bitcast ({ i32 }* @"\01l_entry_point" to i8*), i8* bitcast (i16* @__swift_reflection_version to i8*), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @_swift1_autolink_entries, i32 0, i32 0)], section "llvm.metadata", align 8 +// CHECK-elf: @llvm.used = appending global [5 x i8*] [i8* bitcast (void ()* @frieda to i8*), i8* bitcast (i32 (i32, i8**)* @main to i8*), i8* bitcast ({ i32 }* @"\01l_entry_point" to i8*), i8* bitcast (i16* @__swift_reflection_version to i8*), i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* @_swift1_autolink_entries, i32 0, i32 0)], section "llvm.metadata", align 8 // CHECK: define linkonce_odr hidden swiftcc void @qux() // CHECK: define hidden swiftcc void @fred() From 66059a493588b2bbb157b802f47e5b6fa2dd10a1 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 2 Sep 2020 22:39:19 +0000 Subject: [PATCH 523/663] utils: add a timeout to the integration tests This will allow us to add test cases which may hang. The timeout here is taken from the value we use in the regular test suite (along with the check for the timeout requirements). --- utils/build-script-impl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index bced37215db7b..b68cd47d85d24 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -3124,8 +3124,11 @@ function build_and_test_installable_package() { with_pushd "${PKG_TESTS_SANDBOX_PARENT}" \ call tar xzf "${package_for_host}" + if python -c import psutil ; then + TIMEOUT_ARGS=--timeout=3000 # 50 minutes + fi with_pushd "${PKG_TESTS_SOURCE_DIR}" \ - call python "${LIT_EXECUTABLE_PATH}" . -sv --param package-path="${PKG_TESTS_SANDBOX}" --param test-exec-root="${PKG_TESTS_TEMPS}" --param llvm-bin-dir="${LLVM_BIN_DIR}" + call python "${LIT_EXECUTABLE_PATH}" . -sv --param package-path="${PKG_TESTS_SANDBOX}" --param test-exec-root="${PKG_TESTS_TEMPS}" --param llvm-bin-dir="${LLVM_BIN_DIR}" ${TIMEOUT_ARGS} fi fi } From 8125f772a0155c24eb80f6806ef4a77d1ed52a10 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 2 Sep 2020 15:47:07 -0700 Subject: [PATCH 524/663] Update build-script-impl Reduce timeout to 20m --- utils/build-script-impl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index b68cd47d85d24..97b63b7b2c744 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -3125,7 +3125,7 @@ function build_and_test_installable_package() { call tar xzf "${package_for_host}" if python -c import psutil ; then - TIMEOUT_ARGS=--timeout=3000 # 50 minutes + TIMEOUT_ARGS=--timeout=1200 # 20 minutes fi with_pushd "${PKG_TESTS_SOURCE_DIR}" \ call python "${LIT_EXECUTABLE_PATH}" . -sv --param package-path="${PKG_TESTS_SANDBOX}" --param test-exec-root="${PKG_TESTS_TEMPS}" --param llvm-bin-dir="${LLVM_BIN_DIR}" ${TIMEOUT_ARGS} From 5dd962ceddf9cbc1ae0f0b5fe09a2bb95ffcc715 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 2 Sep 2020 18:47:35 -0400 Subject: [PATCH 525/663] AutoDiff: Remove some unnecessary calls to getInterfaceType() --- lib/SILOptimizer/Differentiation/LinearMapInfo.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp b/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp index 4582c20521d6d..e27b7f38a1a3b 100644 --- a/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp +++ b/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp @@ -141,8 +141,6 @@ LinearMapInfo::createBranchingTraceDecl(SILBasicBlock *originalBB, if (genericSig) branchingTraceDecl->setGenericSignature(genericSig); computeAccessLevel(branchingTraceDecl, original->getEffectiveSymbolLinkage()); - branchingTraceDecl->getInterfaceType(); - assert(branchingTraceDecl->hasInterfaceType()); file.addTopLevelDecl(branchingTraceDecl); // Add basic block enum cases. for (auto *predBB : originalBB->getPredecessorBlocks()) { @@ -165,7 +163,6 @@ LinearMapInfo::createBranchingTraceDecl(SILBasicBlock *originalBB, /*IdentifierLoc*/ loc, DeclName(astCtx.getIdentifier(bbId)), paramList, loc, /*RawValueExpr*/ nullptr, branchingTraceDecl); enumEltDecl->setImplicit(); - enumEltDecl->getInterfaceType(); auto *enumCaseDecl = EnumCaseDecl::create( /*CaseLoc*/ loc, {enumEltDecl}, branchingTraceDecl); enumCaseDecl->setImplicit(); @@ -207,8 +204,6 @@ LinearMapInfo::createLinearMapStruct(SILBasicBlock *originalBB, if (genericSig) linearMapStruct->setGenericSignature(genericSig); computeAccessLevel(linearMapStruct, original->getEffectiveSymbolLinkage()); - linearMapStruct->getInterfaceType(); - assert(linearMapStruct->hasInterfaceType()); file.addTopLevelDecl(linearMapStruct); return linearMapStruct; } From 3fd882cadfc3a73f63b666075f8165a6d89b50bc Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Wed, 2 Sep 2020 17:56:06 -0700 Subject: [PATCH 526/663] [NFC] Rename "storage wrapper var" to "projection var" or "projected value" in property wrapper-related code. --- include/swift/AST/Decl.h | 12 ++++++------ include/swift/AST/PropertyWrappers.h | 10 +++++----- lib/AST/ASTContext.cpp | 4 ++-- lib/AST/Decl.cpp | 8 ++++---- lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/CSDiagnostics.h | 8 ++++---- lib/Sema/CSFix.cpp | 8 ++++---- lib/Sema/CSFix.h | 10 +++++----- lib/Sema/CSSimplify.cpp | 14 +++++++------- lib/Sema/ConstraintSystem.cpp | 10 +++++----- lib/Sema/ConstraintSystem.h | 4 ++-- lib/Sema/LookupVisibleDecls.cpp | 10 +++++----- lib/Sema/TypeCheckDecl.cpp | 2 +- lib/Sema/TypeCheckStorage.cpp | 22 +++++++++++----------- lib/Serialization/Deserialization.cpp | 10 +++++----- lib/Serialization/Serialization.cpp | 4 ++-- 16 files changed, 69 insertions(+), 69 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c9448731e3a85..7bfb4c7c2427a 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4866,9 +4866,9 @@ enum class PropertyWrapperSynthesizedPropertyKind { /// The backing storage property, which is a stored property of the /// wrapper type. Backing, - /// A storage wrapper (e.g., `$foo`), which is a wrapper over the - /// wrapper instance's `projectedValue` property. - StorageWrapper, + /// A projection (e.g., `$foo`), which is a computed property to access the + /// wrapper instance's \c projectedValue property. + Projection, }; /// VarDecl - 'var' and 'let' declarations. @@ -5191,9 +5191,9 @@ class VarDecl : public AbstractStorageDecl { /// bound generic version. VarDecl *getPropertyWrapperBackingProperty() const; - /// Retreive the storage wrapper for a property that has an attached - /// property wrapper. - VarDecl *getPropertyWrapperStorageWrapper() const; + /// Retreive the projection var for a property that has an attached + /// property wrapper with a \c projectedValue . + VarDecl *getPropertyWrapperProjectionVar() const; /// Retrieve the backing storage property for a lazy property. VarDecl *getLazyStorageProperty() const; diff --git a/include/swift/AST/PropertyWrappers.h b/include/swift/AST/PropertyWrappers.h index f1a1b57490234..2f78ad4123d76 100644 --- a/include/swift/AST/PropertyWrappers.h +++ b/include/swift/AST/PropertyWrappers.h @@ -145,9 +145,9 @@ struct PropertyWrapperBackingPropertyInfo { /// The backing property. VarDecl *backingVar = nullptr; - /// The storage wrapper property, if any. When present, this takes the name - /// '$foo' from `backingVar`. - VarDecl *storageWrapperVar = nullptr; + /// The synthesized projection property, if any. When present, this takes the name + /// of the original wrapped property prefixed with \c $ + VarDecl *projectionVar = nullptr; /// An expression that initializes the backing property from a value of /// the original property's type (e.g., via `init(wrappedValue:)`), or @@ -161,10 +161,10 @@ struct PropertyWrapperBackingPropertyInfo { PropertyWrapperBackingPropertyInfo() { } PropertyWrapperBackingPropertyInfo(VarDecl *backingVar, - VarDecl *storageWrapperVar, + VarDecl *projectionVar, Expr *initializeFromOriginal, PropertyWrapperValuePlaceholderExpr *placeholder) - : backingVar(backingVar), storageWrapperVar(storageWrapperVar), + : backingVar(backingVar), projectionVar(projectionVar), initializeFromOriginal(initializeFromOriginal), wrappedValuePlaceholder(placeholder) { } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4a776d6dbb790..21703f4929ce9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4840,8 +4840,8 @@ VarDecl *VarDecl::getOriginalWrappedProperty( case PropertyWrapperSynthesizedPropertyKind::Backing: return this == wrapperInfo.backingVar ? original : nullptr; - case PropertyWrapperSynthesizedPropertyKind::StorageWrapper: - return this == wrapperInfo.storageWrapperVar ? original : nullptr; + case PropertyWrapperSynthesizedPropertyKind::Projection: + return this == wrapperInfo.projectionVar ? original : nullptr; } llvm_unreachable("covered switch"); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ea43c3cc48eb8..57c820f48f4fc 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5908,8 +5908,8 @@ VarDecl::getPropertyWrapperSynthesizedPropertyKind() const { PropertyWrapperSynthesizedPropertyKind::Backing)) return PropertyWrapperSynthesizedPropertyKind::Backing; if (getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) - return PropertyWrapperSynthesizedPropertyKind::StorageWrapper; + PropertyWrapperSynthesizedPropertyKind::Projection)) + return PropertyWrapperSynthesizedPropertyKind::Projection; return None; } @@ -5917,8 +5917,8 @@ VarDecl *VarDecl::getPropertyWrapperBackingProperty() const { return getPropertyWrapperBackingPropertyInfo().backingVar; } -VarDecl *VarDecl::getPropertyWrapperStorageWrapper() const { - return getPropertyWrapperBackingPropertyInfo().storageWrapperVar; +VarDecl *VarDecl::getPropertyWrapperProjectionVar() const { + return getPropertyWrapperBackingPropertyInfo().projectionVar; } VarDecl *VarDecl::getLazyStorageProperty() const { diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 6536516e55959..0e417ab08fe58 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3169,7 +3169,7 @@ bool MissingCallFailure::diagnoseAsError() { } bool ExtraneousPropertyWrapperUnwrapFailure::diagnoseAsError() { - auto newPrefix = usingStorageWrapper() ? "$" : "_"; + auto newPrefix = usingProjection() ? "$" : "_"; if (auto *member = getReferencedMember()) { emitDiagnostic(diag::incorrect_property_wrapper_reference_member, diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 956c91736dd0e..980a8a51b753b 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -974,20 +974,20 @@ class MissingCallFailure final : public FailureDiagnostic { class PropertyWrapperReferenceFailure : public ContextualFailure { VarDecl *Property; - bool UsingStorageWrapper; + bool UsingProjection; public: PropertyWrapperReferenceFailure(const Solution &solution, VarDecl *property, - bool usingStorageWrapper, Type base, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) : ContextualFailure(solution, base, wrapper, locator), Property(property), - UsingStorageWrapper(usingStorageWrapper) {} + UsingProjection(usingProjection) {} VarDecl *getProperty() const { return Property; } Identifier getPropertyName() const { return Property->getName(); } - bool usingStorageWrapper() const { return UsingStorageWrapper; } + bool usingProjection() const { return UsingProjection; } ValueDecl *getReferencedMember() const { auto *locator = getLocator(); diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 80cc9fc225ad6..4add25b21c9f3 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -534,22 +534,22 @@ InsertExplicitCall *InsertExplicitCall::create(ConstraintSystem &cs, bool UsePropertyWrapper::diagnose(const Solution &solution, bool asNote) const { ExtraneousPropertyWrapperUnwrapFailure failure( - solution, Wrapped, UsingStorageWrapper, Base, Wrapper, getLocator()); + solution, Wrapped, UsingProjection, Base, Wrapper, getLocator()); return failure.diagnose(asNote); } UsePropertyWrapper *UsePropertyWrapper::create(ConstraintSystem &cs, VarDecl *wrapped, - bool usingStorageWrapper, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) { return new (cs.getAllocator()) UsePropertyWrapper( - cs, wrapped, usingStorageWrapper, base, wrapper, locator); + cs, wrapped, usingProjection, base, wrapper, locator); } bool UseWrappedValue::diagnose(const Solution &solution, bool asNote) const { MissingPropertyWrapperUnwrapFailure failure(solution, PropertyWrapper, - usingStorageWrapper(), Base, + usingProjection(), Base, Wrapper, getLocator()); return failure.diagnose(asNote); } diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 7bcaf50f85c65..ab4ad6138e363 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -799,15 +799,15 @@ class InsertExplicitCall final : public ConstraintFix { class UsePropertyWrapper final : public ConstraintFix { VarDecl *Wrapped; - bool UsingStorageWrapper; + bool UsingProjection; Type Base; Type Wrapper; UsePropertyWrapper(ConstraintSystem &cs, VarDecl *wrapped, - bool usingStorageWrapper, Type base, Type wrapper, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::UsePropertyWrapper, locator), - Wrapped(wrapped), UsingStorageWrapper(usingStorageWrapper), Base(base), + Wrapped(wrapped), UsingProjection(usingProjection), Base(base), Wrapper(wrapper) {} public: @@ -822,7 +822,7 @@ class UsePropertyWrapper final : public ConstraintFix { } static UsePropertyWrapper *create(ConstraintSystem &cs, VarDecl *wrapped, - bool usingStorageWrapper, Type base, + bool usingProjection, Type base, Type wrapper, ConstraintLocator *locator); }; @@ -836,7 +836,7 @@ class UseWrappedValue final : public ConstraintFix { : ConstraintFix(cs, FixKind::UseWrappedValue, locator), PropertyWrapper(propertyWrapper), Base(base), Wrapper(wrapper) {} - bool usingStorageWrapper() const { + bool usingProjection() const { auto nameStr = PropertyWrapper->getName().str(); return !nameStr.startswith("_"); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1ea9cf08b296a..a6563aa7fa550 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2897,7 +2897,7 @@ static ConstraintFix *fixPropertyWrapperFailure( return nullptr; enum class Fix : uint8_t { - StorageWrapper, + ProjectedValue, PropertyWrapper, WrappedValue, }; @@ -2916,9 +2916,9 @@ static ConstraintFix *fixPropertyWrapperFailure( return nullptr; switch (fix) { - case Fix::StorageWrapper: + case Fix::ProjectedValue: case Fix::PropertyWrapper: - return UsePropertyWrapper::create(cs, decl, fix == Fix::StorageWrapper, + return UsePropertyWrapper::create(cs, decl, fix == Fix::ProjectedValue, baseTy, toType.getValueOr(type), locator); @@ -2929,10 +2929,10 @@ static ConstraintFix *fixPropertyWrapperFailure( llvm_unreachable("Unhandled Fix type in switch"); }; - if (auto storageWrapper = - cs.getStorageWrapperInformation(*resolvedOverload)) { - if (auto *fix = applyFix(Fix::StorageWrapper, storageWrapper->first, - storageWrapper->second)) + if (auto projection = + cs.getPropertyWrapperProjectionInfo(*resolvedOverload)) { + if (auto *fix = applyFix(Fix::ProjectedValue, projection->first, + projection->second)) return fix; } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index f27cc505b4283..11adbd6b897a6 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -956,7 +956,7 @@ getPropertyWrapperInformationFromOverload( } Optional> -ConstraintSystem::getStorageWrapperInformation( +ConstraintSystem::getPropertyWrapperProjectionInfo( SelectedOverload resolvedOverload) { return getPropertyWrapperInformationFromOverload( resolvedOverload, DC, @@ -964,12 +964,12 @@ ConstraintSystem::getStorageWrapperInformation( if (!decl->hasAttachedPropertyWrapper()) return None; - auto storageWrapper = decl->getPropertyWrapperStorageWrapper(); - if (!storageWrapper) + auto projectionVar = decl->getPropertyWrapperProjectionVar(); + if (!projectionVar) return None; - return std::make_pair(storageWrapper, - storageWrapper->getInterfaceType()); + return std::make_pair(projectionVar, + projectionVar->getInterfaceType()); }); } diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 18579bfc857a8..cdf966f1f23c3 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3436,9 +3436,9 @@ class ConstraintSystem { ConstraintLocator::PathElementKind kind) const; /// Gets the VarDecl associateed with resolvedOverload, and the type of the - /// storage wrapper if the decl has an associated storage wrapper. + /// projection if the decl has an associated property wrapper with a projectedValue. Optional> - getStorageWrapperInformation(SelectedOverload resolvedOverload); + getPropertyWrapperProjectionInfo(SelectedOverload resolvedOverload); /// Gets the VarDecl associateed with resolvedOverload, and the type of the /// backing storage if the decl has an associated property wrapper. diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index 53bb7c8c57512..2989603eb708f 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -234,7 +234,7 @@ static void collectVisibleMemberDecls(const DeclContext *CurrDC, LookupState LS, } static void -synthesizePropertyWrapperStorageWrapperProperties(IterableDeclContext *IDC); +synthesizePropertyWrapperVariables(IterableDeclContext *IDC); /// Lookup members in extensions of \p LookupType, using \p BaseType as the /// underlying type when checking any constraints on the extensions. @@ -253,7 +253,7 @@ static void doGlobalExtensionLookup(Type BaseType, extension)), false)) continue; - synthesizePropertyWrapperStorageWrapperProperties(extension); + synthesizePropertyWrapperVariables(extension); collectVisibleMemberDecls(CurrDC, LS, BaseType, extension, FoundDecls); } @@ -538,10 +538,10 @@ static void Consumer, CurrDC, LS, Reason); } -// Generate '$' and '_' prefixed variables that have attached property +// Generate '$' and '_' prefixed variables for members that have attached property // wrappers. static void -synthesizePropertyWrapperStorageWrapperProperties(IterableDeclContext *IDC) { +synthesizePropertyWrapperVariables(IterableDeclContext *IDC) { auto SF = IDC->getAsGenericContext()->getParentSourceFile(); if (!SF || SF->Kind == SourceFileKind::Interface) return; @@ -578,7 +578,7 @@ static void synthesizeMemberDeclsForLookup(NominalTypeDecl *NTD, /*useResolver=*/true); } - synthesizePropertyWrapperStorageWrapperProperties(NTD); + synthesizePropertyWrapperVariables(NTD); } static void lookupVisibleMemberDeclsImpl( diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index e1ac4b7797a4b..9956f191bc4ab 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -582,7 +582,7 @@ IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { // Property wrapper storage wrappers are final if the original property // is final. if (auto *original = VD->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { if (original->isFinal()) return true; } diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 78c4d0b0066b8..4f16d3263ac7f 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -590,7 +590,7 @@ getEnclosingSelfPropertyWrapperAccess(VarDecl *property, bool forProjected) { if (forProjected) { result.accessedProperty = - property->getPropertyWrapperBackingPropertyInfo().storageWrapperVar; + property->getPropertyWrapperBackingPropertyInfo().projectionVar; } else { result.accessedProperty = property; } @@ -1380,7 +1380,7 @@ synthesizeGetterBody(AccessorDecl *getter, ASTContext &ctx) { } if (var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { return synthesizeTrivialGetterBody(getter, TargetImpl::WrapperStorage, ctx); } @@ -1629,7 +1629,7 @@ synthesizeSetterBody(AccessorDecl *setter, ASTContext &ctx) { // Synthesize a setter for the storage wrapper property of a property // with an attached wrapper. if (auto original = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { auto backingVar = original->getPropertyWrapperBackingProperty(); return synthesizeTrivialSetterBodyWithStorage(setter, TargetImpl::WrapperStorage, @@ -1743,7 +1743,7 @@ synthesizeCoroutineAccessorBody(AccessorDecl *accessor, ASTContext &ctx) { } if (var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { target = TargetImpl::WrapperStorage; } } @@ -1961,7 +1961,7 @@ static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage, case PropertyWrapperSynthesizedPropertyKind::Backing: break; - case PropertyWrapperSynthesizedPropertyKind::StorageWrapper: { + case PropertyWrapperSynthesizedPropertyKind::Projection: { if (auto origVar = var->getOriginalWrappedProperty(wrapperSynthesizedKind)) { // The property wrapper info may not actually link back to a wrapper // implementation, if there was a semantic error checking the wrapper. @@ -2261,7 +2261,7 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, } if (auto original = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { auto backingVar = original->getPropertyWrapperBackingProperty(); if (backingVar->getFormalAccess() < var->getFormalAccess()) return false; @@ -2285,7 +2285,7 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, break; } else if (var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) { + PropertyWrapperSynthesizedPropertyKind::Projection)) { break; } } @@ -2381,7 +2381,7 @@ LazyStoragePropertyRequest::evaluate(Evaluator &evaluator, /// Synthesize a computed property `$foo` for a property with an attached /// wrapper that has a `projectedValue` property. -static VarDecl *synthesizePropertyWrapperStorageWrapperProperty( +static VarDecl *synthesizePropertyWrapperProjectionVar( ASTContext &ctx, VarDecl *var, Type wrapperType, VarDecl *wrapperVar) { // If the original property has a @_projectedValueProperty attribute, use @@ -2520,7 +2520,7 @@ PropertyWrapperMutabilityRequest::evaluate(Evaluator &, bool isProjectedValue = false; if (numWrappers < 1) { originalVar = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper); + PropertyWrapperSynthesizedPropertyKind::Projection); if (!originalVar) return None; @@ -2598,7 +2598,7 @@ PropertyWrapperLValuenessRequest::evaluate(Evaluator &, bool isProjectedValue = false; if (numWrappers < 1) { VD = var->getOriginalWrappedProperty( - PropertyWrapperSynthesizedPropertyKind::StorageWrapper); + PropertyWrapperSynthesizedPropertyKind::Projection); numWrappers = 1; // Can't compose projected values isProjectedValue = true; } @@ -2752,7 +2752,7 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, // synthesize a computed property for '$foo'. VarDecl *storageVar = nullptr; if (wrapperInfo.projectedValueVar) { - storageVar = synthesizePropertyWrapperStorageWrapperProperty( + storageVar = synthesizePropertyWrapperProjectionVar( ctx, var, storageInterfaceType, wrapperInfo.projectedValueVar); } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 724aef5da6b76..f2f70f9be2ed0 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2905,13 +2905,13 @@ class DeclDeserializer { } VarDecl *backingVar = cast(backingDecl.get()); - VarDecl *storageWrapperVar = nullptr; + VarDecl *projectionVar = nullptr; if (numBackingProperties > 1) { - storageWrapperVar = cast(MF.getDecl(backingPropertyIDs[1])); + projectionVar = cast(MF.getDecl(backingPropertyIDs[1])); } PropertyWrapperBackingPropertyInfo info( - backingVar, storageWrapperVar, nullptr, nullptr); + backingVar, projectionVar, nullptr, nullptr); ctx.evaluator.cacheOutput( PropertyWrapperBackingPropertyInfoRequest{var}, std::move(info)); ctx.evaluator.cacheOutput( @@ -2919,8 +2919,8 @@ class DeclDeserializer { backingVar->getInterfaceType()); backingVar->setOriginalWrappedProperty(var); - if (storageWrapperVar) - storageWrapperVar->setOriginalWrappedProperty(var); + if (projectionVar) + projectionVar->setOriginalWrappedProperty(var); } return var; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index c8b5946e80f25..5440f26845263 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3312,9 +3312,9 @@ class Serializer::DeclSerializer : public DeclVisitor { ++numBackingProperties; arrayFields.push_back(S.addDeclRef(backingInfo.backingVar)); } - if (backingInfo.storageWrapperVar) { + if (backingInfo.projectionVar) { ++numBackingProperties; - arrayFields.push_back(S.addDeclRef(backingInfo.storageWrapperVar)); + arrayFields.push_back(S.addDeclRef(backingInfo.projectionVar)); } } for (Type dependency : collectDependenciesFromType(ty->getCanonicalType())) From ac63abc8c2d3693c3e89bcc3f0451579992ff3f7 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 2 Sep 2020 21:09:09 -0700 Subject: [PATCH 527/663] [SILGen] Consolidate emission of SILDeclRef definitions Fill in the missing SILDeclRef cases in `emitDelayedFunction`, and rename it to `emitFunctionDefinition`. This will allow SIL to be emitted only for a specific set of symbols. --- lib/SILGen/SILGen.cpp | 183 +++++++++++++++++++++++------------------- lib/SILGen/SILGen.h | 5 +- 2 files changed, 103 insertions(+), 85 deletions(-) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index ecd8482d96768..731038fb28a10 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -676,17 +676,15 @@ bool SILGenModule::hasFunction(SILDeclRef constant) { void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); } -static void emitDelayedFunction(SILGenModule &SGM, - SILDeclRef constant, - SILFunction *f) { +void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { switch (constant.kind) { case SILDeclRef::Kind::Func: { auto *fd = cast(constant.getDecl()); - SGM.preEmitFunction(constant, fd, f, fd); + preEmitFunction(constant, fd, f, fd); PrettyStackTraceSILFunction X("silgen emitFunction", f); - SILGenFunction(SGM, *f, fd).emitFunction(fd); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, fd).emitFunction(fd); + postEmitFunction(constant, f); break; } @@ -696,16 +694,16 @@ static void emitDelayedFunction(SILGenModule &SGM, if (decl->getDeclContext()->getSelfClassDecl() && (decl->isDesignatedInit() || decl->isObjC())) { - SGM.preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, decl, f, decl); PrettyStackTraceSILFunction X("silgen emitConstructor", f); - SILGenFunction(SGM, *f, decl).emitClassConstructorAllocator(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl).emitClassConstructorAllocator(decl); + postEmitFunction(constant, f); } else { - SGM.preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, decl, f, decl); PrettyStackTraceSILFunction X("silgen emitConstructor", f); f->createProfiler(decl, constant, ForDefinition); - SILGenFunction(SGM, *f, decl).emitValueConstructor(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl).emitValueConstructor(decl); + postEmitFunction(constant, f); } break; } @@ -714,11 +712,11 @@ static void emitDelayedFunction(SILGenModule &SGM, auto *decl = cast(constant.getDecl()); assert(decl->getDeclContext()->getSelfClassDecl()); - SGM.preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, decl, f, decl); PrettyStackTraceSILFunction X("silgen constructor initializer", f); f->createProfiler(decl, constant, ForDefinition); - SILGenFunction(SGM, *f, decl).emitClassConstructorInitializer(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl).emitClassConstructorInitializer(decl); + postEmitFunction(constant, f); break; } @@ -731,22 +729,22 @@ static void emitDelayedFunction(SILGenModule &SGM, case DefaultArgumentKind::Normal: { auto arg = param->getTypeCheckedDefaultExpr(); auto loc = RegularLocation::getAutoGeneratedLocation(arg); - SGM.preEmitFunction(constant, arg, f, loc); + preEmitFunction(constant, arg, f, loc); PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f); - SILGenFunction SGF(SGM, *f, initDC); + SILGenFunction SGF(*this, *f, initDC); SGF.emitGeneratorFunction(constant, arg); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } case DefaultArgumentKind::StoredProperty: { auto arg = param->getStoredProperty(); auto loc = RegularLocation::getAutoGeneratedLocation(arg); - SGM.preEmitFunction(constant, arg, f, loc); + preEmitFunction(constant, arg, f, loc); PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f); - SILGenFunction SGF(SGM, *f, initDC); + SILGenFunction SGF(*this, *f, initDC); SGF.emitGeneratorFunction(constant, arg); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } @@ -780,23 +778,23 @@ static void emitDelayedFunction(SILGenModule &SGM, } auto loc = RegularLocation::getAutoGeneratedLocation(init); - SGM.preEmitFunction(constant, init, f, loc); + preEmitFunction(constant, init, f, loc); PrettyStackTraceSILFunction X("silgen emitStoredPropertyInitialization", f); f->createProfiler(init, constant, ForDefinition); - SILGenFunction SGF(SGM, *f, initDC); + SILGenFunction SGF(*this, *f, initDC); // If this is a stored property initializer inside a type at global scope, // it may close over a global variable. If we're emitting top-level code, // then emit a "mark_function_escape" that lists the captured global // variables so that definite initialization can reason about this // escape point. - if (!var->getDeclContext()->isLocalContext() && - SGM.TopLevelSGF && SGM.TopLevelSGF->B.hasValidInsertionPoint()) { - SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(var, captureInfo); + if (!var->getDeclContext()->isLocalContext() && TopLevelSGF && + TopLevelSGF->B.hasValidInsertionPoint()) { + emitMarkFunctionEscapeForTopLevelCodeGlobals(var, captureInfo); } SGF.emitGeneratorFunction(constant, init, /*EmitProfilerIncrement=*/true); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } @@ -804,7 +802,7 @@ static void emitDelayedFunction(SILGenModule &SGM, auto *var = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(var); - SGM.preEmitFunction(constant, var, f, loc); + preEmitFunction(constant, var, f, loc); PrettyStackTraceSILFunction X( "silgen emitPropertyWrapperBackingInitializer", f); auto wrapperInfo = var->getPropertyWrapperBackingPropertyInfo(); @@ -812,26 +810,26 @@ static void emitDelayedFunction(SILGenModule &SGM, f->createProfiler(wrapperInfo.initializeFromOriginal, constant, ForDefinition); auto varDC = var->getInnermostDeclContext(); - SILGenFunction SGF(SGM, *f, varDC); + SILGenFunction SGF(*this, *f, varDC); SGF.emitGeneratorFunction(constant, wrapperInfo.initializeFromOriginal); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } case SILDeclRef::Kind::GlobalAccessor: { auto *global = cast(constant.getDecl()); - auto found = SGM.delayedGlobals.find(global); - assert(found != SGM.delayedGlobals.end()); + auto found = delayedGlobals.find(global); + assert(found != delayedGlobals.end()); auto *onceToken = found->second.first; auto *onceFunc = found->second.second; auto loc = RegularLocation::getAutoGeneratedLocation(global); - SGM.preEmitFunction(constant, global, f, loc); + preEmitFunction(constant, global, f, loc); PrettyStackTraceSILFunction X("silgen emitGlobalAccessor", f); - SILGenFunction(SGM, *f, global->getDeclContext()) + SILGenFunction(*this, *f, global->getDeclContext()) .emitGlobalAccessor(global, onceToken, onceFunc); - SGM.postEmitFunction(constant, f); + postEmitFunction(constant, f); break; } @@ -839,19 +837,63 @@ static void emitDelayedFunction(SILGenModule &SGM, auto *decl = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(decl); - SGM.preEmitFunction(constant, decl, f, loc); + preEmitFunction(constant, decl, f, loc); PrettyStackTraceSILFunction X("silgen enum constructor", f); - SILGenFunction(SGM, *f, decl->getDeclContext()).emitEnumConstructor(decl); - SGM.postEmitFunction(constant, f); + SILGenFunction(*this, *f, decl->getDeclContext()).emitEnumConstructor(decl); + postEmitFunction(constant, f); break; } - case SILDeclRef::Kind::Destroyer: - case SILDeclRef::Kind::Deallocator: - case SILDeclRef::Kind::IVarInitializer: - case SILDeclRef::Kind::IVarDestroyer: - llvm_unreachable("Cannot emit as a delayed function"); - break; + case SILDeclRef::Kind::Destroyer: { + auto *dd = cast(constant.getDecl()); + preEmitFunction(constant, dd, f, dd); + PrettyStackTraceSILFunction X("silgen emitDestroyingDestructor", f); + SILGenFunction(*this, *f, dd).emitDestroyingDestructor(dd); + postEmitFunction(constant, f); + return; + } + + case SILDeclRef::Kind::Deallocator: { + auto *dd = cast(constant.getDecl()); + auto *cd = cast(dd->getDeclContext()); + + if (usesObjCAllocator(cd)) { + preEmitFunction(constant, dd, f, dd); + PrettyStackTraceSILFunction X("silgen emitDestructor -dealloc", f); + f->createProfiler(dd, constant, ForDefinition); + SILGenFunction(*this, *f, dd).emitObjCDestructor(constant); + postEmitFunction(constant, f); + return; + } + + auto loc = RegularLocation::getAutoGeneratedLocation(dd); + preEmitFunction(constant, dd, f, loc); + PrettyStackTraceSILFunction X("silgen emitDeallocatingDestructor", f); + f->createProfiler(dd, constant, ForDefinition); + SILGenFunction(*this, *f, dd).emitDeallocatingDestructor(dd); + postEmitFunction(constant, f); + return; + } + + case SILDeclRef::Kind::IVarInitializer: { + auto *cd = cast(constant.getDecl()); + auto loc = RegularLocation::getAutoGeneratedLocation(cd); + preEmitFunction(constant, cd, f, loc); + PrettyStackTraceSILFunction X("silgen emitDestructor ivar initializer", f); + SILGenFunction(*this, *f, cd).emitIVarInitializer(constant); + postEmitFunction(constant, f); + return; + } + + case SILDeclRef::Kind::IVarDestroyer: { + auto *cd = cast(constant.getDecl()); + auto loc = RegularLocation::getAutoGeneratedLocation(cd); + preEmitFunction(constant, cd, f, loc); + PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f); + SILGenFunction(*this, *f, cd).emitIVarDestroyer(constant); + postEmitFunction(constant, f); + return; + } } } @@ -889,7 +931,7 @@ static void emitOrDelayFunction(SILGenModule &SGM, return; } - emitDelayedFunction(SGM, constant, f); + SGM.emitFunctionDefinition(constant, f); } void SILGenModule::preEmitFunction(SILDeclRef constant, @@ -1232,12 +1274,7 @@ void SILGenModule::emitObjCAllocatorDestructor(ClassDecl *cd, // Destructors are a necessary part of class metadata, so can't be delayed. if (dd->hasBody()) { SILDeclRef dealloc(dd, SILDeclRef::Kind::Deallocator); - SILFunction *f = getFunction(dealloc, ForDefinition); - preEmitFunction(dealloc, dd, f, dd); - PrettyStackTraceSILFunction X("silgen emitDestructor -dealloc", f); - f->createProfiler(dd, dealloc, ForDefinition); - SILGenFunction(*this, *f, dd).emitObjCDestructor(dealloc); - postEmitFunction(dealloc, f); + emitFunctionDefinition(dealloc, getFunction(dealloc, ForDefinition)); } // Emit the Objective-C -dealloc entry point if it has @@ -1249,24 +1286,16 @@ void SILGenModule::emitObjCAllocatorDestructor(ClassDecl *cd, if (requiresIVarInitialization(*this, cd)) { auto ivarInitializer = SILDeclRef(cd, SILDeclRef::Kind::IVarInitializer) .asForeign(); - SILFunction *f = getFunction(ivarInitializer, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(ivarInitializer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestructor ivar initializer", f); - SILGenFunction(*this, *f, cd).emitIVarInitializer(ivarInitializer); - postEmitFunction(ivarInitializer, f); + emitFunctionDefinition(ivarInitializer, + getFunction(ivarInitializer, ForDefinition)); } // Emit the ivar destroyer, if needed. if (hasNonTrivialIVars(cd)) { auto ivarDestroyer = SILDeclRef(cd, SILDeclRef::Kind::IVarDestroyer) .asForeign(); - SILFunction *f = getFunction(ivarDestroyer, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(ivarDestroyer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f); - SILGenFunction(*this, *f, cd).emitIVarDestroyer(ivarDestroyer); - postEmitFunction(ivarDestroyer, f); + emitFunctionDefinition(ivarDestroyer, + getFunction(ivarDestroyer, ForDefinition)); } } @@ -1276,12 +1305,8 @@ void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) { // Emit the ivar destroyer, if needed. if (requiresIVarDestroyer(cd)) { SILDeclRef ivarDestroyer(cd, SILDeclRef::Kind::IVarDestroyer); - SILFunction *f = getFunction(ivarDestroyer, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(ivarDestroyer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f); - SILGenFunction(*this, *f, dd).emitIVarDestroyer(ivarDestroyer); - postEmitFunction(ivarDestroyer, f); + emitFunctionDefinition(ivarDestroyer, + getFunction(ivarDestroyer, ForDefinition)); } // If the class would use the Objective-C allocator, only emit -dealloc. @@ -1294,24 +1319,14 @@ void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) { // Destructors are a necessary part of class metadata, so can't be delayed. if (dd->hasBody()) { SILDeclRef destroyer(dd, SILDeclRef::Kind::Destroyer); - SILFunction *f = getFunction(destroyer, ForDefinition); - RegularLocation loc(dd); - preEmitFunction(destroyer, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDestroyingDestructor", f); - SILGenFunction(*this, *f, dd).emitDestroyingDestructor(dd); - postEmitFunction(destroyer, f); + emitFunctionDefinition(destroyer, getFunction(destroyer, ForDefinition)); } // Emit the deallocating destructor. { SILDeclRef deallocator(dd, SILDeclRef::Kind::Deallocator); - SILFunction *f = getFunction(deallocator, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(deallocator, dd, f, loc); - PrettyStackTraceSILFunction X("silgen emitDeallocatingDestructor", f); - f->createProfiler(dd, deallocator, ForDefinition); - SILGenFunction(*this, *f, dd).emitDeallocatingDestructor(dd); - postEmitFunction(deallocator, f); + emitFunctionDefinition(deallocator, + getFunction(deallocator, ForDefinition)); } } @@ -1910,8 +1925,8 @@ class SILGenModuleRAII { || !SGM.pendingConformances.empty()) { while (!SGM.forcedFunctions.empty()) { auto &front = SGM.forcedFunctions.front(); - emitDelayedFunction(SGM, front, - SGM.getEmittedFunction(front, ForDefinition)); + SGM.emitFunctionDefinition( + front, SGM.getEmittedFunction(front, ForDefinition)); SGM.forcedFunctions.pop_front(); } while (!SGM.pendingConformances.empty()) { diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 5e69eed1488d2..7e2684fd22757 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -270,7 +270,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// curried functions, curried entry point Functions are also generated and /// added to the current SILModule. void emitFunction(FuncDecl *fd); - + + /// Emits the function definition for a given SILDeclRef. + void emitFunctionDefinition(SILDeclRef constant, SILFunction *f); + /// Generates code for the given closure expression and adds the /// SILFunction to the current SILModule under the name SILDeclRef(ce). SILFunction *emitClosure(AbstractClosureExpr *ce); From cc8344aaae926a52749d2f3add3a21d600479f37 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 2 Sep 2020 21:09:09 -0700 Subject: [PATCH 528/663] [SILGen] Remove astNode param from preEmitFunction The AST node can be retrieved from the passed SILLocation. --- lib/SILGen/SILGen.cpp | 65 +++++++++++++++----------------------- lib/SILGen/SILGen.h | 6 +--- lib/SILGen/SILGenThunk.cpp | 7 ++-- 3 files changed, 30 insertions(+), 48 deletions(-) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 731038fb28a10..85702f8dae013 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -681,7 +681,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { case SILDeclRef::Kind::Func: { auto *fd = cast(constant.getDecl()); - preEmitFunction(constant, fd, f, fd); + preEmitFunction(constant, f, fd); PrettyStackTraceSILFunction X("silgen emitFunction", f); SILGenFunction(*this, *f, fd).emitFunction(fd); postEmitFunction(constant, f); @@ -694,12 +694,12 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { if (decl->getDeclContext()->getSelfClassDecl() && (decl->isDesignatedInit() || decl->isObjC())) { - preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, f, decl); PrettyStackTraceSILFunction X("silgen emitConstructor", f); SILGenFunction(*this, *f, decl).emitClassConstructorAllocator(decl); postEmitFunction(constant, f); } else { - preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, f, decl); PrettyStackTraceSILFunction X("silgen emitConstructor", f); f->createProfiler(decl, constant, ForDefinition); SILGenFunction(*this, *f, decl).emitValueConstructor(decl); @@ -712,7 +712,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { auto *decl = cast(constant.getDecl()); assert(decl->getDeclContext()->getSelfClassDecl()); - preEmitFunction(constant, decl, f, decl); + preEmitFunction(constant, f, decl); PrettyStackTraceSILFunction X("silgen constructor initializer", f); f->createProfiler(decl, constant, ForDefinition); SILGenFunction(*this, *f, decl).emitClassConstructorInitializer(decl); @@ -729,7 +729,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { case DefaultArgumentKind::Normal: { auto arg = param->getTypeCheckedDefaultExpr(); auto loc = RegularLocation::getAutoGeneratedLocation(arg); - preEmitFunction(constant, arg, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f); SILGenFunction SGF(*this, *f, initDC); SGF.emitGeneratorFunction(constant, arg); @@ -740,7 +740,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { case DefaultArgumentKind::StoredProperty: { auto arg = param->getStoredProperty(); auto loc = RegularLocation::getAutoGeneratedLocation(arg); - preEmitFunction(constant, arg, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f); SILGenFunction SGF(*this, *f, initDC); SGF.emitGeneratorFunction(constant, arg); @@ -778,7 +778,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { } auto loc = RegularLocation::getAutoGeneratedLocation(init); - preEmitFunction(constant, init, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitStoredPropertyInitialization", f); f->createProfiler(init, constant, ForDefinition); SILGenFunction SGF(*this, *f, initDC); @@ -802,7 +802,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { auto *var = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(var); - preEmitFunction(constant, var, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X( "silgen emitPropertyWrapperBackingInitializer", f); auto wrapperInfo = var->getPropertyWrapperBackingPropertyInfo(); @@ -825,7 +825,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { auto *onceFunc = found->second.second; auto loc = RegularLocation::getAutoGeneratedLocation(global); - preEmitFunction(constant, global, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitGlobalAccessor", f); SILGenFunction(*this, *f, global->getDeclContext()) .emitGlobalAccessor(global, onceToken, onceFunc); @@ -837,7 +837,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { auto *decl = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(decl); - preEmitFunction(constant, decl, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen enum constructor", f); SILGenFunction(*this, *f, decl->getDeclContext()).emitEnumConstructor(decl); postEmitFunction(constant, f); @@ -846,7 +846,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { case SILDeclRef::Kind::Destroyer: { auto *dd = cast(constant.getDecl()); - preEmitFunction(constant, dd, f, dd); + preEmitFunction(constant, f, dd); PrettyStackTraceSILFunction X("silgen emitDestroyingDestructor", f); SILGenFunction(*this, *f, dd).emitDestroyingDestructor(dd); postEmitFunction(constant, f); @@ -858,7 +858,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { auto *cd = cast(dd->getDeclContext()); if (usesObjCAllocator(cd)) { - preEmitFunction(constant, dd, f, dd); + preEmitFunction(constant, f, dd); PrettyStackTraceSILFunction X("silgen emitDestructor -dealloc", f); f->createProfiler(dd, constant, ForDefinition); SILGenFunction(*this, *f, dd).emitObjCDestructor(constant); @@ -867,7 +867,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { } auto loc = RegularLocation::getAutoGeneratedLocation(dd); - preEmitFunction(constant, dd, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitDeallocatingDestructor", f); f->createProfiler(dd, constant, ForDefinition); SILGenFunction(*this, *f, dd).emitDeallocatingDestructor(dd); @@ -878,7 +878,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { case SILDeclRef::Kind::IVarInitializer: { auto *cd = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(cd); - preEmitFunction(constant, cd, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitDestructor ivar initializer", f); SILGenFunction(*this, *f, cd).emitIVarInitializer(constant); postEmitFunction(constant, f); @@ -888,7 +888,7 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { case SILDeclRef::Kind::IVarDestroyer: { auto *cd = cast(constant.getDecl()); auto loc = RegularLocation::getAutoGeneratedLocation(cd); - preEmitFunction(constant, cd, f, loc); + preEmitFunction(constant, f, loc); PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f); SILGenFunction(*this, *f, cd).emitIVarDestroyer(constant); postEmitFunction(constant, f); @@ -934,19 +934,8 @@ static void emitOrDelayFunction(SILGenModule &SGM, SGM.emitFunctionDefinition(constant, f); } -void SILGenModule::preEmitFunction(SILDeclRef constant, - llvm::PointerUnion astNode, - SILFunction *F, +void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F, SILLocation Loc) { - // By default, use the astNode to create the location. - if (Loc.isNull()) { - if (auto *decl = astNode.get()) - Loc = RegularLocation(decl); - else - Loc = RegularLocation(astNode.get()); - } - assert(F->empty() && "already emitted function?!"); if (F->getLoweredFunctionType()->isPolymorphic()) @@ -960,14 +949,12 @@ void SILGenModule::preEmitFunction(SILDeclRef constant, llvm::dbgs() << " : "; F->getLoweredType().print(llvm::dbgs()); llvm::dbgs() << '\n'; - if (astNode) { - if (auto *decl = astNode.dyn_cast()) { - decl->dump(llvm::dbgs()); - } else { - astNode.get()->dump(llvm::dbgs()); - llvm::dbgs() << "\n"; - } + if (auto *decl = Loc.getAsASTNode()) { + decl->dump(llvm::dbgs()); llvm::dbgs() << '\n'; + } else if (auto *expr = Loc.getAsASTNode()) { + expr->dump(llvm::dbgs()); + llvm::dbgs() << "\n"; }); } @@ -1220,7 +1207,7 @@ SILFunction *SILGenModule::emitClosure(AbstractClosureExpr *ce) { // initializer of the containing type. if (!f->isExternalDeclaration()) return f; - preEmitFunction(constant, ce, f, ce); + preEmitFunction(constant, f, ce); PrettyStackTraceSILFunction X("silgen closureexpr", f); SILGenFunction(*this, *f, ce).emitClosure(ce); postEmitFunction(constant, f); @@ -1421,7 +1408,7 @@ void SILGenModule::emitObjCMethodThunk(FuncDecl *method) { // ObjC entry points are always externally usable, so can't be delay-emitted. SILFunction *f = getFunction(thunk, ForDefinition); - preEmitFunction(thunk, method, f, method); + preEmitFunction(thunk, f, method); PrettyStackTraceSILFunction X("silgen emitObjCMethodThunk", f); f->setBare(IsBare); f->setThunk(IsThunk); @@ -1447,7 +1434,7 @@ void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { // delayed. { SILFunction *f = getFunction(getterRef, ForDefinition); - preEmitFunction(getterRef, prop, f, thunkBodyLoc); + preEmitFunction(getterRef, f, thunkBodyLoc); PrettyStackTraceSILFunction X("silgen objc property getter thunk", f); f->setBare(IsBare); f->setThunk(IsThunk); @@ -1463,7 +1450,7 @@ void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { auto setterRef = SILDeclRef(setter, SILDeclRef::Kind::Func).asForeign(); SILFunction *f = getFunction(setterRef, ForDefinition); - preEmitFunction(setterRef, prop, f, thunkBodyLoc); + preEmitFunction(setterRef, f, thunkBodyLoc); PrettyStackTraceSILFunction X("silgen objc property setter thunk", f); f->setBare(IsBare); f->setThunk(IsThunk); @@ -1483,7 +1470,7 @@ void SILGenModule::emitObjCConstructorThunk(ConstructorDecl *constructor) { SILFunction *f = getFunction(thunk, ForDefinition); auto loc = RegularLocation::getAutoGeneratedLocation(constructor); - preEmitFunction(thunk, constructor, f, loc); + preEmitFunction(thunk, f, loc); PrettyStackTraceSILFunction X("silgen objc constructor thunk", f); f->setBare(IsBare); f->setThunk(IsThunk); diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 7e2684fd22757..76708975f8919 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -305,11 +305,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Emits a thunk from a Swift function to the native Swift convention. void emitNativeToForeignThunk(SILDeclRef thunk); - void preEmitFunction(SILDeclRef constant, - llvm::PointerUnion astNode, - SILFunction *F, - SILLocation L); + void preEmitFunction(SILDeclRef constant, SILFunction *F, SILLocation L); void postEmitFunction(SILDeclRef constant, SILFunction *F); /// Add a global variable to the SILModule. diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index 8fd44deec40bc..1cb65e303e5e9 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -95,7 +95,7 @@ void SILGenModule::emitForeignToNativeThunk(SILDeclRef thunk) { f->setThunk(IsThunk); if (thunk.asForeign().isClangGenerated()) f->setSerialized(IsSerializable); - preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl()); + preEmitFunction(thunk, f, thunk.getDecl()); PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f); SILGenFunction(*this, *f, SwiftModule).emitForeignToNativeThunk(thunk); postEmitFunction(thunk, f); @@ -107,10 +107,9 @@ void SILGenModule::emitNativeToForeignThunk(SILDeclRef thunk) { SILFunction *f = getFunction(thunk, ForDefinition); if (thunk.hasDecl()) - preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl()); + preEmitFunction(thunk, f, thunk.getDecl()); else - preEmitFunction(thunk, thunk.getAbstractClosureExpr(), f, - thunk.getAbstractClosureExpr()); + preEmitFunction(thunk, f, thunk.getAbstractClosureExpr()); PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f); f->setBare(IsBare); f->setThunk(IsThunk); From 0f40089f911d755141ee5d9a7d4d9c6d780b01e9 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 2 Sep 2020 21:09:09 -0700 Subject: [PATCH 529/663] [SILGen] Move closure emission to emitFunctionDefinition --- lib/SILGen/SILGen.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 85702f8dae013..004ef7c731e47 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -679,6 +679,14 @@ void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); } void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { switch (constant.kind) { case SILDeclRef::Kind::Func: { + if (auto *ce = constant.getAbstractClosureExpr()) { + preEmitFunction(constant, f, ce); + PrettyStackTraceSILFunction X("silgen closureexpr", f); + SILGenFunction(*this, *f, ce).emitClosure(ce); + postEmitFunction(constant, f); + break; + } + auto *fd = cast(constant.getDecl()); preEmitFunction(constant, f, fd); @@ -1207,10 +1215,8 @@ SILFunction *SILGenModule::emitClosure(AbstractClosureExpr *ce) { // initializer of the containing type. if (!f->isExternalDeclaration()) return f; - preEmitFunction(constant, f, ce); - PrettyStackTraceSILFunction X("silgen closureexpr", f); - SILGenFunction(*this, *f, ce).emitClosure(ce); - postEmitFunction(constant, f); + + emitFunctionDefinition(constant, f); return f; } From da65826692848c4478a7fd6cc6ae0c1c4009917f Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 2 Sep 2020 21:09:10 -0700 Subject: [PATCH 530/663] [SILGen] Remove an obsolete linking hack We already make sure @objc entry-points aren't optimized out. --- lib/SIL/IR/SILDeclRef.cpp | 6 ++---- test/IRGen/objc_local.swift | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index 42c19adb7b30e..5b7ea065750fb 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -233,13 +233,11 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { return forDefinition ? linkage : addExternalToLinkage(linkage); }; - // Native function-local declarations have shared linkage. - // FIXME: @objc declarations should be too, but we currently have no way - // of marking them "used" other than making them external. + // Function-local declarations have private linkage, unless serialized. ValueDecl *d = getDecl(); DeclContext *moduleContext = d->getDeclContext(); while (!moduleContext->isModuleScopeContext()) { - if (!isForeign && moduleContext->isLocalContext()) { + if (moduleContext->isLocalContext()) { return isSerialized() ? SILLinkage::Shared : SILLinkage::Private; } moduleContext = moduleContext->getParent(); diff --git a/test/IRGen/objc_local.swift b/test/IRGen/objc_local.swift index c0d24d2b3fa64..d20e087b0d6f7 100644 --- a/test/IRGen/objc_local.swift +++ b/test/IRGen/objc_local.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %build-irgen-test-overlays // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) %s -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) %s -emit-ir -O | %FileCheck %s // REQUIRES: objc_interop From c4c14ba2de9f297299915346acdce014ba3755f7 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 2 Sep 2020 21:09:10 -0700 Subject: [PATCH 531/663] [SILGen] Cleanup isForeignToNativeThunk slightly Bail early for the foreign case. --- lib/SIL/IR/SILDeclRef.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index 5b7ea065750fb..f91fcb28461a5 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -611,19 +611,23 @@ EffectsKind SILDeclRef::getEffectsAttribute() const { } bool SILDeclRef::isForeignToNativeThunk() const { + // If this isn't a native entry-point, it's not a foreign-to-native thunk. + if (isForeign) + return false; + // Non-decl entry points are never natively foreign, so they would never // have a foreign-to-native thunk. if (!hasDecl()) return false; if (requiresForeignToNativeThunk(getDecl())) - return !isForeign; + return true; // ObjC initializing constructors and factories are foreign. // We emit a special native allocating constructor though. if (isa(getDecl()) && (kind == Kind::Initializer || cast(getDecl())->isFactoryInit()) && getDecl()->hasClangNode()) - return !isForeign; + return true; return false; } From ae5b38566caa4ec0975af1a4da7147782ea9c708 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 2 Sep 2020 21:09:10 -0700 Subject: [PATCH 532/663] [SILGen] Expand isNativeToForeignThunk Expand to other cases where we emit a native-to-foreign thunk, but didn't previously return true. Because this now includes @objc entry-points for methods, adjust the linking logic so it can maintain more restrictive linkages for things like private decls. --- lib/SIL/IR/SILDeclRef.cpp | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index f91fcb28461a5..1b6f2ce79950f 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -247,11 +247,6 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { if (isForeignToNativeThunk()) return SILLinkage::Shared; - // If a function declares a @_cdecl name, its native-to-foreign thunk - // is exported with the visibility of the function. - if (isNativeToForeignThunk() && !d->getAttrs().hasAttribute()) - return SILLinkage::Shared; - // Declarations imported from Clang modules have shared linkage. if (isClangImported()) return SILLinkage::Shared; @@ -327,12 +322,20 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { } } - // Forced-static-dispatch functions are created on-demand and have - // at best shared linkage. if (auto fn = dyn_cast(d)) { + // Forced-static-dispatch functions are created on-demand and have + // at best shared linkage. if (fn->hasForcedStaticDispatch()) { limit = Limit::OnDemand; } + + // Native-to-foreign thunks for top-level decls are created on-demand, + // unless they are marked @_cdecl, in which case they expose a dedicated + // entry-point with the visibility of the function. + if (isNativeToForeignThunk() && !fn->getAttrs().hasAttribute()) { + if (fn->getDeclContext()->isModuleScopeContext()) + limit = Limit::OnDemand; + } } if (isEnumElement()) { @@ -632,17 +635,21 @@ bool SILDeclRef::isForeignToNativeThunk() const { } bool SILDeclRef::isNativeToForeignThunk() const { + // If this isn't a foreign entry-point, it's not a native-to-foreign thunk. + if (!isForeign) + return false; + // We can have native-to-foreign thunks over closures. if (!hasDecl()) - return isForeign; - // We can have native-to-foreign thunks over global or local native functions. - // TODO: Static functions too. - if (auto func = dyn_cast(getDecl())) { - if (!func->getDeclContext()->isTypeContext() - && !func->hasClangNode()) - return isForeign; - } - return false; + return true; + + // A decl with a clang node doesn't have a native entry-point to forward onto. + if (getDecl()->hasClangNode()) + return false; + + // Only certain kinds of SILDeclRef can expose native-to-foreign thunks. + return kind == Kind::Func || kind == Kind::Initializer || + kind == Kind::Deallocator; } /// Use the Clang importer to mangle a Clang declaration. From ef5335ad00e574eea24b3f6061bbf1ef2f3e90eb Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 2 Sep 2020 21:09:11 -0700 Subject: [PATCH 533/663] [SILGen] Move thunk emission to emitFunctionDefinition --- lib/SILGen/SILGen.cpp | 82 ++++++++++++++++++-------------------- lib/SILGen/SILGenThunk.cpp | 25 ++---------- 2 files changed, 43 insertions(+), 64 deletions(-) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 004ef7c731e47..b30a0ff89dcf6 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -677,6 +677,39 @@ bool SILGenModule::hasFunction(SILDeclRef constant) { void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); } void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) { + + if (constant.isForeignToNativeThunk()) { + f->setThunk(IsThunk); + if (constant.asForeign().isClangGenerated()) + f->setSerialized(IsSerializable); + + auto loc = constant.getAsRegularLocation(); + loc.markAutoGenerated(); + auto *dc = loc.getAsDeclContext(); + assert(dc); + + preEmitFunction(constant, f, loc); + PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f); + SILGenFunction(*this, *f, dc).emitForeignToNativeThunk(constant); + postEmitFunction(constant, f); + return; + } + + if (constant.isNativeToForeignThunk()) { + auto loc = constant.getAsRegularLocation(); + loc.markAutoGenerated(); + auto *dc = loc.getAsDeclContext(); + assert(dc); + + preEmitFunction(constant, f, loc); + PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f); + f->setBare(IsBare); + f->setThunk(IsThunk); + SILGenFunction(*this, *f, dc).emitNativeToForeignThunk(constant); + postEmitFunction(constant, f); + return; + } + switch (constant.kind) { case SILDeclRef::Kind::Func: { if (auto *ce = constant.getAbstractClosureExpr()) { @@ -1412,14 +1445,7 @@ void SILGenModule::emitObjCMethodThunk(FuncDecl *method) { return; // ObjC entry points are always externally usable, so can't be delay-emitted. - - SILFunction *f = getFunction(thunk, ForDefinition); - preEmitFunction(thunk, f, method); - PrettyStackTraceSILFunction X("silgen emitObjCMethodThunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, method).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + emitNativeToForeignThunk(thunk); } void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { @@ -1435,18 +1461,9 @@ void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { if (hasFunction(getterRef)) return; - auto thunkBodyLoc = RegularLocation::getAutoGeneratedLocation(prop); // ObjC entry points are always externally usable, so emitting can't be // delayed. - { - SILFunction *f = getFunction(getterRef, ForDefinition); - preEmitFunction(getterRef, f, thunkBodyLoc); - PrettyStackTraceSILFunction X("silgen objc property getter thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, getter).emitNativeToForeignThunk(getterRef); - postEmitFunction(getterRef, f); - } + emitNativeToForeignThunk(getterRef); if (!prop->isSettable(prop->getDeclContext())) return; @@ -1454,14 +1471,7 @@ void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) { // FIXME: Add proper location. auto *setter = prop->getOpaqueAccessor(AccessorKind::Set); auto setterRef = SILDeclRef(setter, SILDeclRef::Kind::Func).asForeign(); - - SILFunction *f = getFunction(setterRef, ForDefinition); - preEmitFunction(setterRef, f, thunkBodyLoc); - PrettyStackTraceSILFunction X("silgen objc property setter thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, setter).emitNativeToForeignThunk(setterRef); - postEmitFunction(setterRef, f); + emitNativeToForeignThunk(setterRef); } void SILGenModule::emitObjCConstructorThunk(ConstructorDecl *constructor) { @@ -1473,15 +1483,7 @@ void SILGenModule::emitObjCConstructorThunk(ConstructorDecl *constructor) { return; // ObjC entry points are always externally usable, so emitting can't be // delayed. - - SILFunction *f = getFunction(thunk, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(constructor); - preEmitFunction(thunk, f, loc); - PrettyStackTraceSILFunction X("silgen objc constructor thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, constructor).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + emitNativeToForeignThunk(thunk); } void SILGenModule::emitObjCDestructorThunk(DestructorDecl *destructor) { @@ -1491,14 +1493,8 @@ void SILGenModule::emitObjCDestructorThunk(DestructorDecl *destructor) { // Don't emit the thunk if it already exists. if (hasFunction(thunk)) return; - SILFunction *f = getFunction(thunk, ForDefinition); - auto loc = RegularLocation::getAutoGeneratedLocation(destructor); - preEmitFunction(thunk, destructor, f, loc); - PrettyStackTraceSILFunction X("silgen objc destructor thunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, destructor).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + + emitNativeToForeignThunk(thunk); } void SILGenModule::visitPatternBindingDecl(PatternBindingDecl *pd) { diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index 1cb65e303e5e9..e2c65ef1ee7be 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -90,31 +90,14 @@ SILGenFunction::emitDynamicMethodRef(SILLocation loc, SILDeclRef constant, void SILGenModule::emitForeignToNativeThunk(SILDeclRef thunk) { // Thunks are always emitted by need, so don't need delayed emission. - assert(!thunk.isForeign && "foreign-to-native thunks only"); - SILFunction *f = getFunction(thunk, ForDefinition); - f->setThunk(IsThunk); - if (thunk.asForeign().isClangGenerated()) - f->setSerialized(IsSerializable); - preEmitFunction(thunk, f, thunk.getDecl()); - PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f); - SILGenFunction(*this, *f, SwiftModule).emitForeignToNativeThunk(thunk); - postEmitFunction(thunk, f); + assert(thunk.isForeignToNativeThunk() && "foreign-to-native thunks only"); + emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition)); } void SILGenModule::emitNativeToForeignThunk(SILDeclRef thunk) { // Thunks are always emitted by need, so don't need delayed emission. - assert(thunk.isForeign && "native-to-foreign thunks only"); - - SILFunction *f = getFunction(thunk, ForDefinition); - if (thunk.hasDecl()) - preEmitFunction(thunk, f, thunk.getDecl()); - else - preEmitFunction(thunk, f, thunk.getAbstractClosureExpr()); - PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f); - f->setBare(IsBare); - f->setThunk(IsThunk); - SILGenFunction(*this, *f, SwiftModule).emitNativeToForeignThunk(thunk); - postEmitFunction(thunk, f); + assert(thunk.isNativeToForeignThunk() && "native-to-foreign thunks only"); + emitFunctionDefinition(thunk, getFunction(thunk, ForDefinition)); } SILValue From fe6d456eec3f457c2ebb1ec0aef13a240fe4b477 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 27 Aug 2020 16:24:32 -0700 Subject: [PATCH 534/663] ARCSequenceOpts: Improve debug print --- lib/SILOptimizer/ARC/ARCBBState.cpp | 28 +++++++++++++++++++ lib/SILOptimizer/ARC/ARCBBState.h | 3 ++ .../ARC/GlobalARCSequenceDataflow.cpp | 27 ++++++++++++++++++ .../ARC/GlobalARCSequenceDataflow.h | 2 ++ .../ARC/GlobalLoopARCSequenceDataflow.cpp | 27 ++++++++++++++++++ .../ARC/GlobalLoopARCSequenceDataflow.h | 2 ++ lib/SILOptimizer/ARC/RCStateTransition.h | 1 - lib/SILOptimizer/ARC/RefCountState.cpp | 22 ++++++++++++++- lib/SILOptimizer/ARC/RefCountState.h | 4 +++ 9 files changed, 114 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/ARC/ARCBBState.cpp b/lib/SILOptimizer/ARC/ARCBBState.cpp index 0b2b0f331ded1..63ddaef0404ae 100644 --- a/lib/SILOptimizer/ARC/ARCBBState.cpp +++ b/lib/SILOptimizer/ARC/ARCBBState.cpp @@ -137,6 +137,34 @@ void ARCBBState::initPredTopDown(ARCBBState &PredBBState) { PtrToTopDownState = PredBBState.PtrToTopDownState; } +void ARCBBState::dumpBottomUpState() { + for (auto state : getBottomupStates()) { + if (!state.hasValue()) + continue; + auto elem = state.getValue(); + if (!elem.first) + continue; + llvm::dbgs() << "SILValue: "; + elem.first->dump(); + llvm::dbgs() << "RefCountState: "; + elem.second.dump(); + } +} + +void ARCBBState::dumpTopDownState() { + for (auto state : getTopDownStates()) { + if (!state.hasValue()) + continue; + auto elem = state.getValue(); + if (!elem.first) + continue; + llvm::dbgs() << "SILValue: "; + elem.first->dump(); + llvm::dbgs() << "RefCountState: "; + elem.second.dump(); + } +} + //===----------------------------------------------------------------------===// // ARCBBStateInfo //===----------------------------------------------------------------------===// diff --git a/lib/SILOptimizer/ARC/ARCBBState.h b/lib/SILOptimizer/ARC/ARCBBState.h index 286c1fc3565ad..e7d3abe5e8d10 100644 --- a/lib/SILOptimizer/ARC/ARCBBState.h +++ b/lib/SILOptimizer/ARC/ARCBBState.h @@ -137,6 +137,9 @@ class ARCSequenceDataflowEvaluator::ARCBBState { /// BB. Used to create an initial state before we merge in other /// predecessors. This is currently a stub. void initPredTopDown(ARCBBState &PredBB); + + void dumpBottomUpState(); + void dumpTopDownState(); }; class ARCSequenceDataflowEvaluator::ARCBBStateInfoHandle { diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp index 5d080626d7a19..e71b0c28a747a 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp @@ -363,9 +363,36 @@ ARCSequenceDataflowEvaluator::ARCSequenceDataflowEvaluator( bool ARCSequenceDataflowEvaluator::run(bool FreezeOwnedReleases) { bool NestingDetected = processBottomUp(FreezeOwnedReleases); NestingDetected |= processTopDown(); + + LLVM_DEBUG( + llvm::dbgs() << "*** Bottom-Up and Top-Down analysis results ***\n"); + LLVM_DEBUG(dumpDataflowResults()); + return NestingDetected; } +void ARCSequenceDataflowEvaluator::dumpDataflowResults() { + llvm::dbgs() << "IncToDecStateMap:\n"; + for (auto it : IncToDecStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Increment: "; + instAndState.first->dump(); + instAndState.second.dump(); + } + + llvm::dbgs() << "DecToIncStateMap:\n"; + for (auto it : DecToIncStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Decrement: "; + instAndState.first->dump(); + instAndState.second.dump(); + } +} + // We put the destructor here so we don't need to expose the type of // BBStateInfo to the outside world. ARCSequenceDataflowEvaluator::~ARCSequenceDataflowEvaluator() = default; diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h index bf9f8281dc5a3..615a755176be0 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h @@ -108,6 +108,8 @@ class ARCSequenceDataflowEvaluator { llvm::Optional getBottomUpBBState(SILBasicBlock *BB); llvm::Optional getTopDownBBState(SILBasicBlock *BB); + + void dumpDataflowResults(); }; } // end swift namespace diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp index 46715ddabf139..883ce1f6dbbdd 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp @@ -252,11 +252,38 @@ LoopARCSequenceDataflowEvaluator::~LoopARCSequenceDataflowEvaluator() { bool LoopARCSequenceDataflowEvaluator::runOnLoop( const LoopRegion *R, bool FreezeOwnedArgEpilogueReleases, bool RecomputePostDomReleases) { + LLVM_DEBUG(llvm::dbgs() << "Run on region:\n"); + LLVM_DEBUG(R->dump(true)); bool NestingDetected = processLoopBottomUp(R, FreezeOwnedArgEpilogueReleases); NestingDetected |= processLoopTopDown(R); + LLVM_DEBUG( + llvm::dbgs() << "*** Bottom-Up and Top-Down analysis results ***\n"); + LLVM_DEBUG(dumpDataflowResults()); return NestingDetected; } +void LoopARCSequenceDataflowEvaluator::dumpDataflowResults() { + llvm::dbgs() << "IncToDecStateMap:\n"; + for (auto it : IncToDecStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Increment: "; + instAndState.first->dump(); + instAndState.second.dump(); + } + + llvm::dbgs() << "DecToIncStateMap:\n"; + for (auto it : DecToIncStateMap) { + if (!it.hasValue()) + continue; + auto instAndState = it.getValue(); + llvm::dbgs() << "Decrement: "; + instAndState.first->dump(); + instAndState.second.dump(); + } +} + void LoopARCSequenceDataflowEvaluator::summarizeLoop( const LoopRegion *R) { RegionStateInfo[R]->summarize(LRFI, RegionStateInfo); diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h index 027e58745f499..ba09d1570ef3d 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h @@ -134,6 +134,8 @@ class LoopARCSequenceDataflowEvaluator { bool processLoopTopDown(const LoopRegion *R); bool processLoopBottomUp(const LoopRegion *R, bool FreezeOwnedArgEpilogueReleases); + + void dumpDataflowResults(); }; } // end swift namespace diff --git a/lib/SILOptimizer/ARC/RCStateTransition.h b/lib/SILOptimizer/ARC/RCStateTransition.h index 65829ff7b9556..7789cb9697f77 100644 --- a/lib/SILOptimizer/ARC/RCStateTransition.h +++ b/lib/SILOptimizer/ARC/RCStateTransition.h @@ -126,7 +126,6 @@ class RCStateTransition { /// Returns a Range of Mutators. Asserts if this transition is not a mutator /// transition. mutator_range getMutators() const { - assert(isMutator() && "This should never be called given mutators"); return {Mutators->begin(), Mutators->end()}; } diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index 76337390c162f..fb8c2ce994c9c 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -903,6 +903,27 @@ void TopDownRefCountState::updateForDifferentLoopInst( // Printing Utilities //===----------------------------------------------------------------------===// +void BottomUpRefCountState::dump() { + llvm::dbgs() << LatState << " " + << (isKnownSafe() ? "KnownSafe" : "NotKnownSafe") << " " + << (isCodeMotionSafe() ? "CodeMotionSafe" : "NotCodeMotionSafe") + << "\n"; + llvm::dbgs() << "Matching Instructions:\n"; + for (auto it : getInstructions()) { + it->dump(); + } +} +void TopDownRefCountState::dump() { + llvm::dbgs() << LatState << " " + << (isKnownSafe() ? "KnownSafe" : "NotKnownSafe") << " " + << (isCodeMotionSafe() ? "CodeMotionSafe" : "NotCodeMotionSafe") + << "\n"; + llvm::dbgs() << "Matching Instructions:\n"; + for (auto it : getInstructions()) { + it->dump(); + } +} + namespace llvm { raw_ostream &operator<<(raw_ostream &OS, @@ -938,5 +959,4 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, llvm_unreachable("Unhandled LatticeState in switch."); } - } // end namespace llvm diff --git a/lib/SILOptimizer/ARC/RefCountState.h b/lib/SILOptimizer/ARC/RefCountState.h index c234ce0680327..e8ab3eae2d1a1 100644 --- a/lib/SILOptimizer/ARC/RefCountState.h +++ b/lib/SILOptimizer/ARC/RefCountState.h @@ -212,6 +212,8 @@ class BottomUpRefCountState : public RefCountState { /// Uninitialize the current state. void clear(); + void dump(); + private: /// Return true if we *might* remove this instruction. /// @@ -354,6 +356,8 @@ class TopDownRefCountState : public RefCountState { /// succeed and false otherwise. bool merge(const TopDownRefCountState &Other); + void dump(); + private: /// Can we guarantee that the given reference counted value has been modified? bool isRefCountStateModified() const; From ce669ca63f2b98703e36caeb6811a299d0954cc8 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Sat, 29 Aug 2020 00:13:53 -0700 Subject: [PATCH 535/663] ARCSequenceOpts: Remove unused args in several functions --- lib/SILOptimizer/ARC/ARCRegionState.cpp | 8 +- .../ARC/GlobalARCSequenceDataflow.cpp | 4 +- lib/SILOptimizer/ARC/RefCountState.cpp | 91 +++++++------------ lib/SILOptimizer/ARC/RefCountState.h | 33 ++----- 4 files changed, 47 insertions(+), 89 deletions(-) diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index 0f60f59fb34b8..0ff903ab7b261 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -208,7 +208,7 @@ static bool processBlockBottomUpInsts( if (Op && OtherState->first == Op) continue; - OtherState->second.updateForSameLoopInst(I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(I, AA); } } @@ -275,7 +275,7 @@ bool ARCRegionState::processLoopBottomUp( continue; for (auto *I : State->getSummarizedInterestingInsts()) - OtherState->second.updateForDifferentLoopInst(I, SetFactory, AA); + OtherState->second.updateForDifferentLoopInst(I, AA); } return false; @@ -361,7 +361,7 @@ bool ARCRegionState::processBlockTopDown( if (Op && OtherState->first == Op) continue; - OtherState->second.updateForSameLoopInst(I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(I, AA); } } @@ -394,7 +394,7 @@ bool ARCRegionState::processLoopTopDown( continue; for (auto *I : State->getSummarizedInterestingInsts()) - OtherState->second.updateForDifferentLoopInst(I, SetFactory, AA); + OtherState->second.updateForDifferentLoopInst(I, AA); } return false; diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp index e71b0c28a747a..9c7728966896a 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp @@ -108,7 +108,7 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { if (Op && OtherState->first == Op) continue; - OtherState->second.updateForSameLoopInst(&I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(&I, AA); } } @@ -260,7 +260,7 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( if (Op && OtherState->first == Op) continue; - OtherState->second.updateForSameLoopInst(&I, SetFactory, AA); + OtherState->second.updateForSameLoopInst(&I, AA); } } diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index fb8c2ce994c9c..dc7858fd4066d 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -195,9 +195,7 @@ bool BottomUpRefCountState::valueCanBeUsedGivenLatticeState() const { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. -bool BottomUpRefCountState::handleUser( - SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +bool BottomUpRefCountState::handleUser() { assert(valueCanBeUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); @@ -233,9 +231,7 @@ valueCanBeGuaranteedUsedGivenLatticeState() const { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. -bool BottomUpRefCountState::handleGuaranteedUser( - SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +bool BottomUpRefCountState::handleGuaranteedUser() { assert(valueCanBeGuaranteedUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); @@ -270,14 +266,12 @@ bool BottomUpRefCountState::isRefCountInstMatchedToTrackedInstruction( if (!Transition.matchingInst(RefCountInst)) return false; - return handleRefCountInstMatch(RefCountInst); + return handleRefCountInstMatch(); } /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. -bool -BottomUpRefCountState:: -handleRefCountInstMatch(SILInstruction *RefCountInst) { +bool BottomUpRefCountState::handleRefCountInstMatch() { // Otherwise modify the state appropriately in preparation for removing the // increment, decrement pair. switch (LatState) { @@ -340,8 +334,7 @@ bool BottomUpRefCountState::merge(const BottomUpRefCountState &Other) { // the value we are tracking. If so advance the state's sequence appropriately // and return true. Otherwise return false. bool BottomUpRefCountState::handlePotentialGuaranteedUser( - SILInstruction *PotentialGuaranteedUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { + SILInstruction *PotentialGuaranteedUser, AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) return false; @@ -375,7 +368,7 @@ bool BottomUpRefCountState::handlePotentialGuaranteedUser( FoundNonARCUser = true; // Otherwise, update the ref count state given the guaranteed user. - return handleGuaranteedUser(getRCRoot(), SetFactory, AA); + return handleGuaranteedUser(); } /// Check if PotentialDecrement can decrement the reference count associated @@ -408,9 +401,8 @@ bool BottomUpRefCountState::handlePotentialDecrement( // Check if PotentialUser could be a use of the reference counted value that // requires user to be alive. If so advance the state's sequence // appropriately and return true. Otherwise return false. -bool BottomUpRefCountState::handlePotentialUser( - SILInstruction *PotentialUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +bool BottomUpRefCountState::handlePotentialUser(SILInstruction *PotentialUser, + AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) @@ -434,12 +426,11 @@ bool BottomUpRefCountState::handlePotentialUser( if (mustUseValue(PotentialUser, getRCRoot(), AA)) FoundNonARCUser = true; - return handleUser(getRCRoot(), SetFactory, AA); + return handleUser(); } -void BottomUpRefCountState::updateForSameLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +void BottomUpRefCountState::updateForSameLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If this state is not tracking anything, there is nothing to update. if (!isTrackingRefCount()) return; @@ -448,7 +439,7 @@ void BottomUpRefCountState::updateForSameLoopInst( // instruction in a way that requires us to guarantee the lifetime of the // pointer up to this point. This has the effect of performing a use and a // decrement. - if (handlePotentialGuaranteedUser(I, SetFactory, AA)) { + if (handlePotentialGuaranteedUser(I, AA)) { LLVM_DEBUG(llvm::dbgs() << " Found Potential Guaranteed Use:\n " << getRCRoot()); return; @@ -465,15 +456,14 @@ void BottomUpRefCountState::updateForSameLoopInst( // Otherwise check if the reference counted value we are tracking // could be used by the given instruction. - if (!handlePotentialUser(I, SetFactory, AA)) + if (!handlePotentialUser(I, AA)) return; LLVM_DEBUG(llvm::dbgs() << " Found Potential Use:\n " << getRCRoot()); } -void BottomUpRefCountState::updateForDifferentLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +void BottomUpRefCountState::updateForDifferentLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If we are not tracking anything, bail. if (!isTrackingRefCount()) return; @@ -483,7 +473,7 @@ void BottomUpRefCountState::updateForDifferentLoopInst( mayDecrementRefCount(I, getRCRoot(), AA)) { LLVM_DEBUG(llvm::dbgs() << " Found potential guaranteed use:\n " << getRCRoot()); - handleGuaranteedUser(getRCRoot(), SetFactory, AA); + handleGuaranteedUser(); return; } } @@ -491,7 +481,7 @@ void BottomUpRefCountState::updateForDifferentLoopInst( // We can just handle potential users normally, since if we handle the user we // already saw a decrement implying that we will treat this like a guaranteed // use. - if (!handlePotentialUser(I, SetFactory, AA)) + if (!handlePotentialUser(I, AA)) return; LLVM_DEBUG(llvm::dbgs() << " Found Potential Use:\n " << getRCRoot()); @@ -585,9 +575,7 @@ bool TopDownRefCountState::valueCanBeDecrementedGivenLatticeState() const { /// If advance the state's sequence appropriately for a decrement. If we do /// advance return true. Otherwise return false. -bool TopDownRefCountState::handleDecrement( - SILInstruction *PotentialDecrement, - ImmutablePointerSetFactory &SetFactory) { +bool TopDownRefCountState::handleDecrement() { switch (LatState) { case LatticeState::Incremented: LatState = LatticeState::MightBeDecremented; @@ -618,9 +606,7 @@ bool TopDownRefCountState::valueCanBeUsedGivenLatticeState() const { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. -bool TopDownRefCountState::handleUser(SILInstruction *PotentialUser, - SILValue RCIdentity, - AliasAnalysis *AA) { +bool TopDownRefCountState::handleUser() { assert(valueCanBeUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); @@ -657,10 +643,7 @@ valueCanBeGuaranteedUsedGivenLatticeState() const { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. -bool TopDownRefCountState::handleGuaranteedUser( - SILInstruction *PotentialGuaranteedUser, - SILValue RCIdentity, ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA) { +bool TopDownRefCountState::handleGuaranteedUser() { assert(valueCanBeGuaranteedUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); // Advance the sequence... @@ -694,13 +677,12 @@ bool TopDownRefCountState::isRefCountInstMatchedToTrackedInstruction( if (!Transition.matchingInst(RefCountInst)) return false; - return handleRefCountInstMatch(RefCountInst); + return handleRefCountInstMatch(); } /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. -bool TopDownRefCountState:: -handleRefCountInstMatch(SILInstruction *RefCountInst) { +bool TopDownRefCountState::handleRefCountInstMatch() { // Otherwise modify the state appropriately in preparation for removing the // increment, decrement pair. switch (LatState) { @@ -762,8 +744,7 @@ bool TopDownRefCountState::merge(const TopDownRefCountState &Other) { // the value we are tracking. If so advance the state's sequence appropriately // and return true. Otherwise return false. bool TopDownRefCountState::handlePotentialGuaranteedUser( - SILInstruction *PotentialGuaranteedUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { + SILInstruction *PotentialGuaranteedUser, AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) return false; @@ -789,16 +770,14 @@ bool TopDownRefCountState::handlePotentialGuaranteedUser( } // Otherwise, update our step given that we have a potential decrement. - return handleGuaranteedUser(PotentialGuaranteedUser, getRCRoot(), - SetFactory, AA); + return handleGuaranteedUser(); } // Check if PotentialDecrement can decrement the reference count associated with // the value we are tracking. If so advance the state's sequence appropriately // and return true. Otherwise return false. bool TopDownRefCountState::handlePotentialDecrement( - SILInstruction *PotentialDecrement, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { + SILInstruction *PotentialDecrement, AliasAnalysis *AA) { // If we are not tracking a ref count, just return false. if (!isTrackingRefCount()) return false; @@ -817,7 +796,7 @@ bool TopDownRefCountState::handlePotentialDecrement( return false; // Otherwise, update our state given the potential decrement. - return handleDecrement(PotentialDecrement, SetFactory); + return handleDecrement(); } // Check if PotentialUser could be a use of the reference counted value that @@ -840,12 +819,11 @@ bool TopDownRefCountState::handlePotentialUser(SILInstruction *PotentialUser, if (!mayHaveSymmetricInterference(PotentialUser, getRCRoot(), AA)) return false; - return handleUser(PotentialUser, getRCRoot(), AA); + return handleUser(); } -void TopDownRefCountState::updateForSameLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +void TopDownRefCountState::updateForSameLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If we are not tracking anything, bail. if (!isTrackingRefCount()) return; @@ -854,7 +832,7 @@ void TopDownRefCountState::updateForSameLoopInst( // instruction in a way that requires us to guarantee the lifetime of the // pointer up to this point. This has the effect of performing a use and a // decrement. - if (handlePotentialGuaranteedUser(I, SetFactory, AA)) { + if (handlePotentialGuaranteedUser(I, AA)) { LLVM_DEBUG(llvm::dbgs() << " Found Potential Guaranteed Use:\n " << getRCRoot()); return; @@ -863,7 +841,7 @@ void TopDownRefCountState::updateForSameLoopInst( // Check if the instruction we are visiting could potentially decrement // the reference counted value we are tracking in a manner that could // cause us to change states. If we do change states continue... - if (handlePotentialDecrement(I, SetFactory, AA)) { + if (handlePotentialDecrement(I, AA)) { LLVM_DEBUG(llvm::dbgs() << " Found Potential Decrement:\n " << getRCRoot()); return; @@ -877,9 +855,8 @@ void TopDownRefCountState::updateForSameLoopInst( << getRCRoot()); } -void TopDownRefCountState::updateForDifferentLoopInst( - SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA) { +void TopDownRefCountState::updateForDifferentLoopInst(SILInstruction *I, + AliasAnalysis *AA) { // If we are not tracking anything, bail. if (!isTrackingRefCount()) return; @@ -888,7 +865,7 @@ void TopDownRefCountState::updateForDifferentLoopInst( if (mayGuaranteedUseValue(I, getRCRoot(), AA) || mayDecrementRefCount(I, getRCRoot(), AA)) { LLVM_DEBUG(llvm::dbgs() << " Found potential guaranteed use!\n"); - handleGuaranteedUser(I, getRCRoot(), SetFactory, AA); + handleGuaranteedUser(); return; } } diff --git a/lib/SILOptimizer/ARC/RefCountState.h b/lib/SILOptimizer/ARC/RefCountState.h index e8ab3eae2d1a1..3cfe6978b728c 100644 --- a/lib/SILOptimizer/ARC/RefCountState.h +++ b/lib/SILOptimizer/ARC/RefCountState.h @@ -188,7 +188,6 @@ class BottomUpRefCountState : public RefCountState { /// Update this reference count's state given the instruction \p I. void updateForSameLoopInst(SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Update this reference count's state given the instruction \p I. @@ -198,7 +197,6 @@ class BottomUpRefCountState : public RefCountState { /// guaranteed used. We treat any uses as regular uses. void updateForDifferentLoopInst( SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Attempt to merge \p Other into this ref count state. Return true if we @@ -243,16 +241,13 @@ class BottomUpRefCountState : public RefCountState { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. - bool handleUser(SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); + bool handleUser(); /// Check if PotentialUser could be a use of the reference counted value that /// requires user to be alive. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialUser(SILInstruction *PotentialUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Returns true if given the current lattice state, do we care if the value @@ -261,22 +256,18 @@ class BottomUpRefCountState : public RefCountState { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. - bool - handleGuaranteedUser(SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); + bool handleGuaranteedUser(); /// Check if PotentialGuaranteedUser can use the reference count associated /// with the value we are tracking. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialGuaranteedUser( SILInstruction *User, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. - bool handleRefCountInstMatch(SILInstruction *RefCountInst); + bool handleRefCountInstMatch(); }; //===----------------------------------------------------------------------===// @@ -335,7 +326,6 @@ class TopDownRefCountState : public RefCountState { /// Update this reference count's state given the instruction \p I. void updateForSameLoopInst(SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Update this reference count's state given the instruction \p I. @@ -345,7 +335,6 @@ class TopDownRefCountState : public RefCountState { /// guaranteed used. We treat any uses as regular uses. void updateForDifferentLoopInst( SILInstruction *I, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Returns true if the passed in ref count inst matches the ref count inst @@ -368,15 +357,13 @@ class TopDownRefCountState : public RefCountState { /// If advance the state's sequence appropriately for a decrement. If we do /// advance return true. Otherwise return false. - bool handleDecrement(SILInstruction *PotentialDecrement, - ImmutablePointerSetFactory &SetFactory); + bool handleDecrement(); /// Check if PotentialDecrement can decrement the reference count associated /// with the value we are tracking. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialDecrement( SILInstruction *PotentialDecrement, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// Returns true if given the current lattice state, do we care if the value @@ -385,8 +372,7 @@ class TopDownRefCountState : public RefCountState { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. - bool handleUser(SILInstruction *PotentialUser, - SILValue RCIdentity, AliasAnalysis *AA); + bool handleUser(); /// Check if PotentialUser could be a use of the reference counted value that /// requires user to be alive. If so advance the state's sequence @@ -399,23 +385,18 @@ class TopDownRefCountState : public RefCountState { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. - bool - handleGuaranteedUser(SILInstruction *PotentialGuaranteedUser, - SILValue RCIdentity, - ImmutablePointerSetFactory &SetFactory, - AliasAnalysis *AA); + bool handleGuaranteedUser(); /// Check if PotentialGuaranteedUser can use the reference count associated /// with the value we are tracking. If so advance the state's sequence /// appropriately and return true. Otherwise return false. bool handlePotentialGuaranteedUser( SILInstruction *PotentialGuaranteedUser, - ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); /// We have a matching ref count inst. Return true if we advance the sequence /// and false otherwise. - bool handleRefCountInstMatch(SILInstruction *RefCountInst); + bool handleRefCountInstMatch(); }; // These static asserts are here for performance reasons. From 132d49f5bc0aff0d5f2a95adbccbc00cca04fb94 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Sat, 29 Aug 2020 10:52:05 -0700 Subject: [PATCH 536/663] ARCSequenceOpts: Minor code consolidation --- lib/SILOptimizer/ARC/ARCRegionState.cpp | 42 +++++++++---------------- lib/SILOptimizer/ARC/ARCRegionState.h | 3 -- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index 0ff903ab7b261..77688c2a2c547 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -156,13 +156,21 @@ void ARCRegionState::mergePredTopDown(ARCRegionState &PredRegionState) { // Bottom Up Dataflow // -static bool processBlockBottomUpInsts( - ARCRegionState &State, SILBasicBlock &BB, - BottomUpDataflowRCStateVisitor &DataflowVisitor, - AliasAnalysis *AA, ImmutablePointerSetFactory &SetFactory) { +bool ARCRegionState::processBlockBottomUp( + const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, + EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, + bool FreezeOwnedArgEpilogueReleases, + BlotMapVector &IncToDecStateMap, + ImmutablePointerSetFactory &SetFactory) { + LLVM_DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n"); - auto II = State.summarizedinterestinginsts_rbegin(); - auto IE = State.summarizedinterestinginsts_rend(); + SILBasicBlock &BB = *R->getBlock(); + BottomUpDataflowRCStateVisitor DataflowVisitor( + RCIA, EAFI, *this, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, + SetFactory); + + auto II = summarizedinterestinginsts_rbegin(); + auto IE = summarizedinterestinginsts_rend(); // If we do not have any interesting instructions, bail and return false since // we can not have any nested instructions. @@ -198,7 +206,7 @@ static bool processBlockBottomUpInsts( // For all other (reference counted value, ref count state) we are // tracking... - for (auto &OtherState : State.getBottomupStates()) { + for (auto &OtherState : getBottomupStates()) { // If the other state's value is blotted, skip it. if (!OtherState.hasValue()) continue; @@ -215,26 +223,6 @@ static bool processBlockBottomUpInsts( return NestingDetected; } -bool ARCRegionState::processBlockBottomUp( - const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, - EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, - bool FreezeOwnedArgEpilogueReleases, - BlotMapVector &IncToDecStateMap, - ImmutablePointerSetFactory &SetFactory) { - LLVM_DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n"); - - SILBasicBlock &BB = *R->getBlock(); - BottomUpDataflowRCStateVisitor DataflowVisitor( - RCIA, EAFI, *this, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, - SetFactory); - - // Visit each arc relevant instruction I in BB visited in reverse... - bool NestingDetected = - processBlockBottomUpInsts(*this, BB, DataflowVisitor, AA, SetFactory); - - return NestingDetected; -} - // Returns true if any of the non-local successors of the region are leaking // blocks. We currently do not handle early exits, but do handle trapping // blocks. Returns false if otherwise diff --git a/lib/SILOptimizer/ARC/ARCRegionState.h b/lib/SILOptimizer/ARC/ARCRegionState.h index 6facbb7d57cbe..3e8a25e2c6fbe 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.h +++ b/lib/SILOptimizer/ARC/ARCRegionState.h @@ -219,9 +219,6 @@ class ARCRegionState { void removeInterestingInst(SILInstruction *I); private: - void processBlockBottomUpPredTerminators( - const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, - ImmutablePointerSetFactory &SetFactory); bool processBlockBottomUp( const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, From 586de0af75bbb0aeccf5f5257ed7e871ae06663d Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Mon, 31 Aug 2020 00:04:23 -0700 Subject: [PATCH 537/663] Fix KnownSafety optimization bugs in ARCSequenceOpts While doing bottom up dataflow, if we encounter an unmatched retain instruction, that can pair with a 'KnownSafe' already visited release instruction, we turn off KnownSafety if the two RCIdentities mayAlias. This is done in BottomUpRefCountState::checkAndResetKnownSafety. In order to determine if a retain is umatched, we look at IncToDecStateMap. If a retain was matched during bottom up dataflow, it is always found in IncToDecStateMap with value of the matched release's BottomUpRefCountState. Similarly, during top down dataflow, if we encounter an unmatched release instruction, that can pair with a 'KnownSafe' already visited retain instruction, we turn off KnownSafety if the two RCIdentities mayAlias. This is done in TopDownRefCountState::checkAndResetKnownSafety. In order to determine if a release is umatched, we look at DecToIncStateMap. If a release was matched during top down dataflow, it is always found in DecToIncStateMap with value of the matched retain's TopDownRefCountState. For ARCLoopOpts, during bottom up and top down traversal of a region with a nested loop, we find if the retain/release in the loop summary was matched or not by looking at the persistent RefCountInstToMatched map. This map is populated when processing the nested loop region from the IncToDecStateMap/DecToStateMap which gets thrown away after the loop region is processed. This fixes the bugs in both ARCSequenceOpts without loop support and with loop support. --- lib/SILOptimizer/ARC/ARCRegionState.cpp | 53 ++- lib/SILOptimizer/ARC/ARCRegionState.h | 13 +- lib/SILOptimizer/ARC/ARCSequenceOpts.cpp | 1 + .../ARC/GlobalARCSequenceDataflow.cpp | 24 +- .../ARC/GlobalLoopARCSequenceDataflow.cpp | 42 ++- .../ARC/GlobalLoopARCSequenceDataflow.h | 7 + lib/SILOptimizer/ARC/RefCountState.cpp | 64 +++- lib/SILOptimizer/ARC/RefCountState.h | 23 +- test/SILOptimizer/OSLogFullOptTest.swift | 2 + .../arcsequenceopts_knownsafebugs.sil | 205 +++++++++++ .../arcsequenceopts_knownsafebugs_loop.sil | 323 ++++++++++++++++++ 11 files changed, 732 insertions(+), 25 deletions(-) create mode 100644 test/SILOptimizer/arcsequenceopts_knownsafebugs.sil create mode 100644 test/SILOptimizer/arcsequenceopts_knownsafebugs_loop.sil diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index 77688c2a2c547..c076b0ec198b2 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -204,6 +204,12 @@ bool ARCRegionState::processBlockBottomUp( // that the instruction "visits". SILValue Op = Result.RCIdentity; + std::function checkIfRefCountInstIsMatched = + [&IncToDecStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return IncToDecStateMap.find(Inst) != IncToDecStateMap.end(); + }; + // For all other (reference counted value, ref count state) we are // tracking... for (auto &OtherState : getBottomupStates()) { @@ -217,6 +223,8 @@ bool ARCRegionState::processBlockBottomUp( continue; OtherState->second.updateForSameLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } @@ -245,8 +253,9 @@ static bool hasEarlyExits( bool ARCRegionState::processLoopBottomUp( const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, + RCIdentityFunctionInfo *RCIA, llvm::DenseMap &RegionStateInfo, - ImmutablePointerSetFactory &SetFactory) { + llvm::DenseSet &UnmatchedRefCountInsts) { ARCRegionState *State = RegionStateInfo[R]; // If we find that we have non-leaking early exits, clear state @@ -256,14 +265,23 @@ bool ARCRegionState::processLoopBottomUp( return false; } + std::function checkIfRefCountInstIsMatched = + [&UnmatchedRefCountInsts](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return UnmatchedRefCountInsts.find(Inst) == UnmatchedRefCountInsts.end(); + }; + // For each state that we are currently tracking, apply our summarized // instructions to it. for (auto &OtherState : getBottomupStates()) { if (!OtherState.hasValue()) continue; - for (auto *I : State->getSummarizedInterestingInsts()) + for (auto *I : State->getSummarizedInterestingInsts()) { OtherState->second.updateForDifferentLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); + } } return false; @@ -273,6 +291,7 @@ bool ARCRegionState::processBottomUp( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &IncToDecStateMap, llvm::DenseMap &RegionStateInfo, ImmutablePointerSetFactory &SetFactory) { @@ -281,7 +300,8 @@ bool ARCRegionState::processBottomUp( // We only process basic blocks for now. This ensures that we always propagate // the empty set from loops. if (!R->isBlock()) - return processLoopBottomUp(R, AA, LRFI, RegionStateInfo, SetFactory); + return processLoopBottomUp(R, AA, LRFI, RCIA, RegionStateInfo, + UnmatchedRefCountInsts); return processBlockBottomUp(R, AA, RCIA, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, SetFactory); @@ -337,6 +357,12 @@ bool ARCRegionState::processBlockTopDown( // that the instruction "visits". SILValue Op = Result.RCIdentity; + std::function checkIfRefCountInstIsMatched = + [&DecToIncStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return DecToIncStateMap.find(Inst) != DecToIncStateMap.end(); + }; + // For all other [(SILValue, TopDownState)] we are tracking... for (auto &OtherState : getTopDownStates()) { // If the other state's value is blotted, skip it. @@ -350,6 +376,8 @@ bool ARCRegionState::processBlockTopDown( continue; OtherState->second.updateForSameLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } @@ -358,8 +386,8 @@ bool ARCRegionState::processBlockTopDown( bool ARCRegionState::processLoopTopDown( const LoopRegion *R, ARCRegionState *State, AliasAnalysis *AA, - LoopRegionFunctionInfo *LRFI, - ImmutablePointerSetFactory &SetFactory) { + LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA, + llvm::DenseSet &UnmatchedRefCountInsts) { assert(R->isLoop() && "We assume we are processing a loop"); @@ -375,14 +403,23 @@ bool ARCRegionState::processLoopTopDown( assert(PredRegion->isBlock() && "Expected the predecessor region to be a " "block"); + std::function checkIfRefCountInstIsMatched = + [&UnmatchedRefCountInsts](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return UnmatchedRefCountInsts.find(Inst) == UnmatchedRefCountInsts.end(); + }; + // For each state that we are currently tracking, apply our summarized // instructions to it. for (auto &OtherState : getTopDownStates()) { if (!OtherState.hasValue()) continue; - for (auto *I : State->getSummarizedInterestingInsts()) + for (auto *I : State->getSummarizedInterestingInsts()) { OtherState->second.updateForDifferentLoopInst(I, AA); + OtherState->second.checkAndResetKnownSafety( + I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); + } } return false; @@ -391,6 +428,7 @@ bool ARCRegionState::processLoopTopDown( bool ARCRegionState::processTopDown( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, LoopRegionFunctionInfo *LRFI, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &DecToIncStateMap, llvm::DenseMap &RegionStateInfo, ImmutablePointerSetFactory &SetFactory) { @@ -399,7 +437,8 @@ bool ARCRegionState::processTopDown( // We only process basic blocks for now. This ensures that we always propagate // the empty set from loops. if (!R->isBlock()) - return processLoopTopDown(R, RegionStateInfo[R], AA, LRFI, SetFactory); + return processLoopTopDown(R, RegionStateInfo[R], AA, LRFI, RCIA, + UnmatchedRefCountInsts); return processBlockTopDown(*R->getBlock(), AA, RCIA, DecToIncStateMap, SetFactory); diff --git a/lib/SILOptimizer/ARC/ARCRegionState.h b/lib/SILOptimizer/ARC/ARCRegionState.h index 3e8a25e2c6fbe..c55af4604ed6a 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.h +++ b/lib/SILOptimizer/ARC/ARCRegionState.h @@ -188,6 +188,7 @@ class ARCRegionState { bool processTopDown( AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, LoopRegionFunctionInfo *LRFI, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &DecToIncStateMap, llvm::DenseMap &LoopRegionState, ImmutablePointerSetFactory &SetFactory); @@ -200,6 +201,7 @@ class ARCRegionState { AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, EpilogueARCFunctionInfo *EAFI, LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, + llvm::DenseSet &UnmatchedRefCountInsts, BlotMapVector &IncToDecStateMap, llvm::DenseMap &RegionStateInfo, ImmutablePointerSetFactory &SetFactory); @@ -227,17 +229,18 @@ class ARCRegionState { ImmutablePointerSetFactory &SetFactory); bool processLoopBottomUp( const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, + RCIdentityFunctionInfo *RCIA, llvm::DenseMap &RegionStateInfo, - ImmutablePointerSetFactory &SetFactory); + llvm::DenseSet &UnmatchedRefCountInsts); bool processBlockTopDown( SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, BlotMapVector &DecToIncStateMap, ImmutablePointerSetFactory &SetFactory); - bool - processLoopTopDown(const LoopRegion *R, ARCRegionState *State, - AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, - ImmutablePointerSetFactory &SetFactory); + bool processLoopTopDown( + const LoopRegion *R, ARCRegionState *State, AliasAnalysis *AA, + LoopRegionFunctionInfo *LRFI, RCIdentityFunctionInfo *RCIA, + llvm::DenseSet &UnmatchedRefCountInsts); void summarizeLoop( const LoopRegion *R, LoopRegionFunctionInfo *LRFI, diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index f628be8b5b29c..827b59d82d57b 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -156,6 +156,7 @@ bool LoopARCPairingContext::processRegion(const LoopRegion *Region, } MadeChange |= MatchedPair; + Evaluator.saveMatchingInfo(Region); Evaluator.clearLoopState(Region); Context.DecToIncStateMap.clear(); Context.IncToDecStateMap.clear(); diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp index 9c7728966896a..1e851075f9719 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp @@ -76,6 +76,12 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { } } + std::function checkIfRefCountInstIsMatched = + [&DecToIncStateMap = DecToIncStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return DecToIncStateMap.find(Inst) != DecToIncStateMap.end(); + }; + // For each instruction I in BB... for (auto &I : BB) { @@ -94,7 +100,7 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { // This SILValue may be null if we were unable to find a specific RCIdentity // that the instruction "visits". - SILValue Op = Result.RCIdentity; + SILValue CurrentRC = Result.RCIdentity; // For all other [(SILValue, TopDownState)] we are tracking... for (auto &OtherState : BBState.getTopDownStates()) { @@ -105,10 +111,12 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { // If we visited an increment or decrement successfully (and thus Op is // set), if this is the state for this operand, skip it. We already // processed it. - if (Op && OtherState->first == Op) + if (CurrentRC && OtherState->first == CurrentRC) continue; OtherState->second.updateForSameLoopInst(&I, AA); + OtherState->second.checkAndResetKnownSafety( + &I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } @@ -221,6 +229,12 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( RCIA, EAFI, BBState, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, SetFactory); + std::function checkIfRefCountInstIsMatched = + [&IncToDecStateMap = IncToDecStateMap](SILInstruction *Inst) { + assert(isa(Inst) || isa(Inst)); + return IncToDecStateMap.find(Inst) != IncToDecStateMap.end(); + }; + auto II = BB.rbegin(); if (!isARCSignificantTerminator(&cast(*II))) { II++; @@ -246,7 +260,7 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( // This SILValue may be null if we were unable to find a specific RCIdentity // that the instruction "visits". - SILValue Op = Result.RCIdentity; + SILValue CurrentRC = Result.RCIdentity; // For all other (reference counted value, ref count state) we are // tracking... @@ -257,10 +271,12 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( // If this is the state associated with the instruction that we are // currently visiting, bail. - if (Op && OtherState->first == Op) + if (CurrentRC && OtherState->first == CurrentRC) continue; OtherState->second.updateForSameLoopInst(&I, AA); + OtherState->second.checkAndResetKnownSafety( + &I, OtherState->first, checkIfRefCountInstIsMatched, RCIA, AA); } } diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp index 883ce1f6dbbdd..108af5d805848 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp @@ -110,7 +110,8 @@ bool LoopARCSequenceDataflowEvaluator::processLoopTopDown(const LoopRegion *R) { // Then perform the dataflow. NestingDetected |= SubregionData.processTopDown( - AA, RCFI, LRFI, DecToIncStateMap, RegionStateInfo, SetFactory); + AA, RCFI, LRFI, UnmatchedRefCountInsts, DecToIncStateMap, + RegionStateInfo, SetFactory); } return NestingDetected; @@ -214,8 +215,9 @@ bool LoopARCSequenceDataflowEvaluator::processLoopBottomUp( // Then perform the region optimization. NestingDetected |= SubregionData.processBottomUp( - AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, - RegionStateInfo, SetFactory); + AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, + UnmatchedRefCountInsts, IncToDecStateMap, RegionStateInfo, + SetFactory); } return NestingDetected; @@ -284,8 +286,7 @@ void LoopARCSequenceDataflowEvaluator::dumpDataflowResults() { } } -void LoopARCSequenceDataflowEvaluator::summarizeLoop( - const LoopRegion *R) { +void LoopARCSequenceDataflowEvaluator::summarizeLoop(const LoopRegion *R) { RegionStateInfo[R]->summarize(LRFI, RegionStateInfo); } @@ -314,3 +315,34 @@ void LoopARCSequenceDataflowEvaluator::removeInterestingInst( auto *Region = LRFI->getRegion(I->getParent()); RegionStateInfo[Region]->removeInterestingInst(I); } + +// Compute if a RefCountInst was unmatched and populate in the persistent +// UnmatchedRefCountInsts. +// This can be done by looking up the RefCountInst in IncToDecStateMap or +// DecToIncStateMap. If the StrongIncrement was matched to a StrongDecrement, +// it will be found in IncToDecStateMap. If the StrongDecrement was matched to +// a StrongIncrement, it will be found in DecToIncStateMap. +void LoopARCSequenceDataflowEvaluator::saveMatchingInfo(const LoopRegion *R) { + if (R->isFunction()) + return; + for (unsigned SubregionID : R->getSubregions()) { + auto *Subregion = LRFI->getRegion(SubregionID); + if (!Subregion->isBlock()) + continue; + auto *RegionState = RegionStateInfo[Subregion]; + for (auto Inst : RegionState->getSummarizedInterestingInsts()) { + if (isa(Inst) || isa(Inst)) { + // unmatched if not found in IncToDecStateMap + if (IncToDecStateMap.find(Inst) == IncToDecStateMap.end()) + UnmatchedRefCountInsts.insert(Inst); + continue; + } + if (isa(Inst) || isa(Inst)) { + // unmatched if not found in DecToIncStateMap + if (DecToIncStateMap.find(Inst) == DecToIncStateMap.end()) + UnmatchedRefCountInsts.insert(Inst); + continue; + } + } + } +} diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h index ba09d1570ef3d..09f86131b5ba4 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h @@ -72,6 +72,9 @@ class LoopARCSequenceDataflowEvaluator { /// Stashed information for each region. llvm::DenseMap RegionStateInfo; + /// Set of unmatched RefCountInsts + llvm::DenseSet UnmatchedRefCountInsts; + public: LoopARCSequenceDataflowEvaluator( SILFunction &F, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, @@ -108,6 +111,10 @@ class LoopARCSequenceDataflowEvaluator { /// Remove \p I from the interesting instruction list of its parent block. void removeInterestingInst(SILInstruction *I); + /// Compute if a RefCountInst was unmatched and populate the persistent + /// UnmatchedRefCountInsts set. + void saveMatchingInfo(const LoopRegion *R); + /// Clear the folding node set of the set factory we have stored internally. void clearSetFactory() { SetFactory.clear(); diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index dc7858fd4066d..1ffba9f5a38a2 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -118,7 +118,7 @@ bool BottomUpRefCountState::mightRemoveMutators() { // We will not remove mutators if we have a might be decremented value that // is not known safe. - return LatState != LatticeState::MightBeDecremented || isKnownSafe(); + return isCodeMotionSafe() || isKnownSafe(); } /// Uninitialize the current state. @@ -462,6 +462,37 @@ void BottomUpRefCountState::updateForSameLoopInst(SILInstruction *I, << getRCRoot()); } +// Remove "KnownSafe" on the BottomUpRefCountState. If we find another unmatched +// retain instruction with a different aliasing RCIdentity or the same +// RCIdentity in the child region in the loop case. +void BottomUpRefCountState::checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA) { + assert(VisitedRC); + // If the RefCountState was not marked "KnownSafe", there is nothing to do. + if (!isKnownSafe()) + return; + assert(Transition.getKind() == RCStateTransitionKind::StrongDecrement); + // We only care about retain instructions that can potentially pair with a + // previously visited release. + if (!(isa(I) || isa(I))) + return; + SILValue VisitingRC = RCIA->getRCIdentityRoot(I->getOperand(0)); + assert(VisitingRC); + // If the visiting retain instruction was not already pair with a release + // instruction, return. + if (checkIfRefCountInstIsMatched(I)) + return; + // If the VisitingRC and VisitedRC do not alias, they cannot be incorrectly + // paired. + if (AA->isNoAlias(VisitingRC, VisitedRC)) + return; + LLVM_DEBUG(llvm::dbgs() << "Clearing KnownSafe for: "); + LLVM_DEBUG(VisitedRC->dump()); + clearKnownSafe(); +} + void BottomUpRefCountState::updateForDifferentLoopInst(SILInstruction *I, AliasAnalysis *AA) { // If we are not tracking anything, bail. @@ -855,6 +886,37 @@ void TopDownRefCountState::updateForSameLoopInst(SILInstruction *I, << getRCRoot()); } +// Remove "KnownSafe" on the TopDownRefCountState. If we find another unmatched +// release instruction with a different aliasing RCIdentity or the same +// RCIdentity in the child region in the loop case. +void TopDownRefCountState::checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA) { + assert(VisitedRC); + // If the RefCountState was not marked "KnownSafe", there is nothing to do. + if (!isKnownSafe()) + return; + assert(Transition.getKind() == RCStateTransitionKind::StrongIncrement); + // We only care about release instructions that can potentially pair with a + // previously visited retain. + if (!(isa(I) || isa(I))) + return; + SILValue VisitingRC = RCIA->getRCIdentityRoot(I->getOperand(0)); + assert(VisitingRC); + // If the visiting release instruction was already pair with a retain + // instruction, return. + if (checkIfRefCountInstIsMatched(I)) + return; + // If the VisitingRC and VisitedRC do not alias, they cannot be incorrectly + // paired. + if (AA->isNoAlias(VisitingRC, VisitedRC)) + return; + LLVM_DEBUG(llvm::dbgs() << "Clearing KnownSafe for: "); + LLVM_DEBUG(VisitedRC->dump()); + clearKnownSafe(); +} + void TopDownRefCountState::updateForDifferentLoopInst(SILInstruction *I, AliasAnalysis *AA) { // If we are not tracking anything, bail. diff --git a/lib/SILOptimizer/ARC/RefCountState.h b/lib/SILOptimizer/ARC/RefCountState.h index 3cfe6978b728c..bc9e2e46e81cc 100644 --- a/lib/SILOptimizer/ARC/RefCountState.h +++ b/lib/SILOptimizer/ARC/RefCountState.h @@ -14,12 +14,13 @@ #define SWIFT_SILOPTIMIZER_PASSMANAGER_ARC_REFCOUNTSTATE_H #include "RCStateTransition.h" -#include "swift/Basic/type_traits.h" +#include "swift/Basic/BlotMapVector.h" #include "swift/Basic/ImmutablePointerSet.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/Basic/type_traits.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" -#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" @@ -134,6 +135,8 @@ class RefCountState { void updateKnownSafe(bool NewValue) { KnownSafe |= NewValue; } + + void clearKnownSafe() { KnownSafe = false; } }; //===----------------------------------------------------------------------===// @@ -189,6 +192,13 @@ class BottomUpRefCountState : public RefCountState { void updateForSameLoopInst(SILInstruction *I, AliasAnalysis *AA); + /// Remove "KnownSafe" on the BottomUpRefCountState, if we find a retain + /// instruction with another RCIdentity can pair with the previously visited + /// retain instruction. + void checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA); /// Update this reference count's state given the instruction \p I. // @@ -327,6 +337,13 @@ class TopDownRefCountState : public RefCountState { void updateForSameLoopInst(SILInstruction *I, AliasAnalysis *AA); + /// Remove "KnownSafe" on the TopDownRefCountState, if we find a retain + /// instruction with another RCIdentity can pair with the previously visited + /// retain instruction. + void checkAndResetKnownSafety( + SILInstruction *I, SILValue VisitedRC, + std::function checkIfRefCountInstIsMatched, + RCIdentityFunctionInfo *RCIA, AliasAnalysis *AA); /// Update this reference count's state given the instruction \p I. /// diff --git a/test/SILOptimizer/OSLogFullOptTest.swift b/test/SILOptimizer/OSLogFullOptTest.swift index 4dbf39e3e886c..8cc72d891f5e1 100644 --- a/test/SILOptimizer/OSLogFullOptTest.swift +++ b/test/SILOptimizer/OSLogFullOptTest.swift @@ -126,6 +126,7 @@ func testNSObjectInterpolation(nsArray: NSArray) { // CHECK-NEXT: bitcast %TSo7NSArrayC* %0 to i8* // CHECK-NEXT: tail call i8* @llvm.objc.retain // CHECK-NEXT: [[NSARRAY_ARG:%.+]] = tail call i8* @llvm.objc.retain + // CHECK: tail call %swift.refcounted* @swift_retain // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] @@ -136,6 +137,7 @@ func testNSObjectInterpolation(nsArray: NSArray) { // CHECK: [[EXIT]]: // CHECK-NEXT: tail call void @llvm.objc.release(i8* [[NSARRAY_ARG]]) + // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: ret void // CHECK: [[ENABLED]]: diff --git a/test/SILOptimizer/arcsequenceopts_knownsafebugs.sil b/test/SILOptimizer/arcsequenceopts_knownsafebugs.sil new file mode 100644 index 0000000000000..25be828929ef6 --- /dev/null +++ b/test/SILOptimizer/arcsequenceopts_knownsafebugs.sil @@ -0,0 +1,205 @@ +// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts %s | %FileCheck %s +sil_stage canonical + +import Builtin +import Swift + +final class ChildCls { + var id: Int + init(_ i:Int) +} + +struct S { + var child1 : ChildCls + var child2 : ChildCls + init() +} + +class Cls { + var child1 : ChildCls + var child2 : ChildCls + init() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject : +// CHECK: bb0(%0 : $S): +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject' +sil hidden @$unmatched_rr_subobject : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_subobject : +// CHECK: bb0(%0 : $S): +// CHECK-NOT: retain_value %0 : $S +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $S +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_subobject' +sil hidden @$matched_rr_subobject : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_retain %1 : $ChildCls + strong_release %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_aliasing : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_aliasing' +sil hidden @$unmatched_rr_aliasing : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_aliasing : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK-NOT: retain_value %0 : $S +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $S +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_aliasing' +sil hidden @$matched_rr_aliasing : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_retain %1 : $ChildCls + strong_release %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_cls_subobject : +// CHECK: bb0(%0 : $Cls): +// CHECK: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK: release_value %0 : $Cls +// CHECK: release_value %0 : $Cls +// CHECK-LABEL: } // end sil function '$unmatched_rr_cls_subobject' +sil hidden @$unmatched_rr_cls_subobject : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_release %2 : $ChildCls + strong_retain %2 : $ChildCls + br bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_cls_subobject : +// CHECK: bb0(%0 : $Cls): +// CHECK-NOT: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $Cls +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_cls_subobject' +sil hidden @$matched_rr_cls_subobject : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_retain %2 : $ChildCls + strong_release %2 : $ChildCls + br bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject_nested_knownsafety : +// CHECK: bb0(%0 : $S): +// CHECK: retain_value %0 : $S +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject_nested_knownsafety' +sil hidden @$unmatched_rr_subobject_nested_knownsafety : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + br bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + diff --git a/test/SILOptimizer/arcsequenceopts_knownsafebugs_loop.sil b/test/SILOptimizer/arcsequenceopts_knownsafebugs_loop.sil new file mode 100644 index 0000000000000..2ba87e801f5b9 --- /dev/null +++ b/test/SILOptimizer/arcsequenceopts_knownsafebugs_loop.sil @@ -0,0 +1,323 @@ +// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=1 -arc-sequence-opts %s | %FileCheck %s +sil_stage canonical + +import Builtin +import Swift + +final class ChildCls { + var id: Int + init(_ i:Int) +} +struct S { + var child1 : ChildCls + var child2 : ChildCls + init() +} +class Cls { + var child1 : ChildCls + var child2 : ChildCls + init() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK: strong_retain %0 : $Cls +// CHECK: bb2: +// CHECK: strong_release %0 : $Cls +// CHECK: strong_release %0 : $Cls +// CHECK-LABEL: } // end sil function '$unmatched_rr_loop' +sil hidden @$unmatched_rr_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_release %0 : $Cls + strong_retain %0 : $Cls + cond_br undef, bb1, bb2 + +bb2: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK-NOT: strong_retain %0 : $Cls +// CHECK: bb2: +// CHECK-NEXT: strong_release %0 : $Cls +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_loop' +sil hidden @$matched_rr_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_retain %0 : $Cls + strong_release %0 : $Cls + cond_br undef, bb1, bb2 + +bb2: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_aliasing_loop : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_aliasing_loop' +sil hidden @$unmatched_rr_aliasing_loop : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_aliasing_loop : +// CHECK: bb0(%0 : $S, %1 : $ChildCls): +// CHECK-NOT: retain_value %0 : $S +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $S +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_aliasing_loop' +sil hidden @$matched_rr_aliasing_loop : $@convention(thin) (@owned S, ChildCls) -> () { +bb0(%0 : $S, %1 : $ChildCls): + retain_value %0 : $S + br bb1 + +bb1: + strong_retain %1 : $ChildCls + strong_release %1 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK: release_value %0 : $Cls +// CHECK: release_value %0 : $Cls +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject_loop' +sil hidden @$unmatched_rr_subobject_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_release %2 : $ChildCls + strong_retain %2 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$matched_rr_subobject_loop : +// CHECK: bb0(%0 : $Cls): +// CHECK-NOT: retain_value %0 : $Cls +// CHECK: bb2: +// CHECK-NEXT: release_value %0 : $Cls +// CHECK-NEXT: [[RET:%.*]] = tuple () +// CHECK-NEXT: return [[RET]] +// CHECK-LABEL: } // end sil function '$matched_rr_subobject_loop' +sil hidden @$matched_rr_subobject_loop : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + retain_value %0 : $Cls + br bb1 + +bb1: + %1 = ref_element_addr %0 : $Cls, #Cls.child1 + %2 = load %1 : $*ChildCls + strong_retain %2 : $ChildCls + strong_release %2 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $Cls + release_value %0 : $Cls + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_subobject_nested_knownsafety_loop : +// CHECK: bb0(%0 : $S): +// CHECK: retain_value %0 : $S +// CHECK: retain_value %0 : $S +// CHECK: bb2: +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK: release_value %0 : $S +// CHECK-LABEL: } // end sil function '$unmatched_rr_subobject_nested_knownsafety_loop' +sil hidden @$unmatched_rr_subobject_nested_knownsafety_loop : $@convention(thin) (@owned S) -> () { +bb0(%0 : $S): + retain_value %0 : $S + retain_value %0 : $S + br bb1 + +bb1: + %1 = struct_extract %0 : $S, #S.child1 + strong_release %1 : $ChildCls + strong_retain %1 : $ChildCls + cond_br undef, bb1, bb2 + +bb2: + release_value %0 : $S + release_value %0 : $S + release_value %0 : $S + %ret = tuple() + return %ret : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_loop_early_exit : +// CHECK: bb1 +// CHECK: strong_release %0 : $Cls +// CHECK: cond_br undef, bb3, bb2 +// CHECK: bb3: +// CHECK: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$unmatched_rr_loop_early_exit' +sil hidden @$unmatched_rr_loop_early_exit : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_release %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_retain %0 : $Cls + cond_br undef, bb1, bb3 + +bb3: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// This case does not get optimized by KnownSafety as well. +// This is because the ref count state gets cleared due to non local successors while merging successors of bb1. +// So the retain/release within the loop do not get matched. And KnownSafety outside the loop gets cleared. +// CHECK-LABEL: sil hidden @$matched_rr_loop_early_exit : +// CHECK: bb1 +// CHECK: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb3, bb2 +// CHECK: bb3: +// CHECK: strong_release %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$matched_rr_loop_early_exit' +sil hidden @$matched_rr_loop_early_exit : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_retain %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_release %0 : $Cls + cond_br undef, bb1, bb3 + +bb3: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// CHECK-LABEL: sil hidden @$unmatched_rr_loop_early_exit_allowsleaks : +// CHECK: bb1 +// CHECK: strong_release %0 : $Cls +// CHECK: cond_br undef, bb2, bb3 +// CHECK: bb2: +// CHECK: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$unmatched_rr_loop_early_exit_allowsleaks' +sil hidden @$unmatched_rr_loop_early_exit_allowsleaks : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_release %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_retain %0 : $Cls + cond_br undef, bb1, bb4 + +bb3: + unreachable + +bb4: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} + +// Unlike $matched_rr_loop_early_exit this case gets optimized due to KnownSafety +// Since AllowsLeaks is set, we do not clear ref count state on seeing the non local successor in bb1 +// CHECK-LABEL: sil hidden @$matched_rr_loop_early_exit_allowsleaks : +// CHECK: bb1 +// CHECK-NOT: strong_release %0 : $Cls +// CHECK: cond_br undef, bb2, bb3 +// CHECK: bb2: +// CHECK-NOT: strong_retain %0 : $Cls +// CHECK: cond_br undef, bb1, bb4 +// CHECK-LABEL: } // end sil function '$matched_rr_loop_early_exit_allowsleaks' +sil hidden @$matched_rr_loop_early_exit_allowsleaks : $@convention(thin) (@owned Cls) -> () { +bb0(%0 : $Cls): + strong_retain %0 : $Cls + br bb1 + +bb1: + strong_retain %0 : $Cls + cond_br undef, bb2, bb3 + +bb2: + strong_release %0 : $Cls + cond_br undef, bb1, bb4 + +bb3: + unreachable + +bb4: + strong_release %0 : $Cls + strong_release %0 : $Cls + %4 = tuple() + return %4 : $() +} From e524b1cb629090c6c45fe54dd1af7f21aeb3c2a7 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 3 Sep 2020 11:24:20 +0100 Subject: [PATCH 538/663] docs: Add WebAssembly.md describing target implementation details (#33723) Only general intro and the "Relative Pointers" section are added to get started. More sections to be added in the future after preliminary feedback on this document is gathered. Related to SR-9307 --- docs/WebAssembly.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 docs/WebAssembly.md diff --git a/docs/WebAssembly.md b/docs/WebAssembly.md new file mode 100644 index 0000000000000..b8b730f813342 --- /dev/null +++ b/docs/WebAssembly.md @@ -0,0 +1,29 @@ +# WebAssembly support in Swift + +WebAssembly is a platform that significantly differs from hardware platforms that Swift already supports. +While it's a virtual machine, there are considerations to be taken into account when targeting it: + +* WebAssembly is still at an early stage, so many features you'd be expect from other platforms are not +available yet, specifically: + 1. `wasm64` variant is not specified yet, only the 32-bit `wasm32` variant is supported in WebAssembly + hosts such as browsers. + 2. While a preview of multi-threading and atomics is available in some browsers and stand-alone + WebAssembly hosts, [the corresponding proposal](https://github.com/WebAssembly/threads/) haven't + formally reached the implementation phase yet. + 3. Dynamic linking is not formally specified and tooling for it is not available yet. +* Binary size is a high priority requirement. Since WebAssembly payloads are usually served in browsers, +one wouldn't want end users to download multi-megabyte binaries. + +Nevertheless, an early implementation of the WebAssembly target is available [in a separate +fork](https://github.com/SwiftWasm). Here we're describing some decisions that were made while developing +the implementation. + +## Relative Pointers + +Relative pointers are used in Swift runtime, but currently it's not feasible to use them for the WebAssembly +target due to the design of WebAssembly and lack of LLVM support. If LLVM supported subtraction relocation +type on WebAssembly like `R_X86_64_PC32` or `X86_64_RELOC_SUBTRACTOR`, this issue can be solved easily. + +Since `R_X86_64_PC32` and `X86_64_RELOC_SUBTRACTOR` are mainly used to generate PIC but WebAssembly doesn't +require PIC because it doesn't support dynamic linking. In addition, the memory space also begins at 0, so +it's unnecessary to relocate at load time. All absolute addresses can be embedded in wasm binary file directly. From 2fc39f673ff8e8ebe7732eeaed01c51b454f5ab3 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 3 Sep 2020 08:54:55 -0700 Subject: [PATCH 539/663] build: merge changes for rebranching Update the `build-windows.bat` script for the re-branch changes. --- utils/build-windows.bat | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/utils/build-windows.bat b/utils/build-windows.bat index 3c9c11e65ff49..a524e3ff01f14 100644 --- a/utils/build-windows.bat +++ b/utils/build-windows.bat @@ -176,6 +176,7 @@ cmake^ -DLLVM_ENABLE_OCAMLDOC:BOOL=NO^ -DLLVM_ENABLE_LIBXML2:BOOL=NO^ -DLLVM_ENABLE_ZLIB:BOOL=NO^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -DENABLE_X86_RELAX_RELOCATIONS:BOOL=YES^ -DLLVM_INSTALL_BINUTILS_SYMLINKS:BOOL=YES^ -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ @@ -232,6 +233,7 @@ cmake^ -DSWIFT_PATH_TO_CMARK_SOURCE:PATH=%source_root%\cmark^ -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH=%source_root%\swift-corelibs-libdispatch^ -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -DSWIFT_INCLUDE_DOCS:BOOL=NO^ -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE:PATH=%source_root%\icu-%icu_version%\include\unicode^ -DSWIFT_WINDOWS_x86_64_ICU_UC:PATH=%source_root%\icu-%icu_version%\lib64\icuuc.lib^ @@ -277,8 +279,8 @@ cmake^ -B "%build_root%\lldb"^ -G Ninja^ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=clang-cl^ - -DCMAKE_CXX_COMPILER=clang-cl^ + -DCMAKE_C_COMPILER=cl^ + -DCMAKE_CXX_COMPILER=cl^ -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ @@ -291,6 +293,7 @@ cmake^ -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ -DLLDB_DISABLE_PYTHON=YES^ -DLLDB_INCLUDE_TESTS:BOOL=NO^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -S "%source_root%\lldb" %exitOnError% cmake --build "%build_root%\lldb" %exitOnError% From 9f01742d944df1f6a53653c046a7a597893dbe63 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 3 Sep 2020 09:38:46 -0700 Subject: [PATCH 540/663] Update build-script-impl Fix quoting --- utils/build-script-impl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 97b63b7b2c744..07bd48ba9c0dc 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -3124,7 +3124,7 @@ function build_and_test_installable_package() { with_pushd "${PKG_TESTS_SANDBOX_PARENT}" \ call tar xzf "${package_for_host}" - if python -c import psutil ; then + if python -c "import psutil" ; then TIMEOUT_ARGS=--timeout=1200 # 20 minutes fi with_pushd "${PKG_TESTS_SOURCE_DIR}" \ From b7c19656ab5751b3f224e8aa4f1d3901809840fa Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 1 Sep 2020 10:10:03 -0700 Subject: [PATCH 541/663] [Serialization] Minor ModuleFile/ModuleFileSharedCore improvements * Add properties to ModuleFile which holds information from the control block. * 'ExtendedValidationInfo' parameter for 'ModuleFileSharedCore::load()' cannot be 'nullptr'. Make it non-defaulted Rvalue reference. --- lib/Serialization/ModuleFile.cpp | 2 +- lib/Serialization/ModuleFile.h | 22 +++++++++++++++++- lib/Serialization/ModuleFileSharedCore.cpp | 10 +++++--- lib/Serialization/ModuleFileSharedCore.h | 24 ++++++++++++++------ lib/Serialization/SerializedModuleLoader.cpp | 12 +++++----- 5 files changed, 52 insertions(+), 18 deletions(-) diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 5b5d0947659f1..3bb3eec65fc55 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -357,7 +357,7 @@ ModuleFile::getModuleName(ASTContext &Ctx, StringRef modulePath, nullptr, nullptr, /*isFramework*/isFramework, loadedModuleFile, - &ExtInfo); + ExtInfo); Name = loadedModuleFile->Name.str(); return std::move(moduleBuf.get()); } diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index 8a0c296a17a0c..413bd6a7d574a 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -438,11 +438,31 @@ class ModuleFile return Core->CompatibilityVersion; } + /// Whether this module is compiled with `-enable-private-imports`. + bool arePrivateImportsEnabled() const { + return Core->Bits.ArePrivateImportsEnabled; + } + /// Is this module file actually a .sib file? .sib files are serialized SIL at /// arbitrary granularity and arbitrary stage; unlike serialized Swift /// modules, which are assumed to contain canonical SIL for an entire module. bool isSIB() const { - return Core->IsSIB; + return Core->Bits.IsSIB; + } + + /// Whether this module file is compiled with '-enable-testing'. + bool isTestable() const { + return Core->Bits.IsTestable; + } + + /// Whether the module is resilient. ('-enable-library-evolution') + ResilienceStrategy getResilienceStrategy() const { + return ResilienceStrategy(Core->Bits.ResilienceStrategy); + } + + /// Whether this module is compiled with implicit dynamic. + bool isImplicitDynamicEnabled() const { + return Core->Bits.IsImplicitDynamicEnabled; } /// Associates this module file with the AST node representing it. diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index aa0adae1f635d..1f08740a8a50a 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -1088,7 +1088,7 @@ ModuleFileSharedCore::ModuleFileSharedCore( std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, bool isFramework, serialization::ValidationInfo &info, - serialization::ExtendedValidationInfo *extInfo) + serialization::ExtendedValidationInfo &extInfo) : ModuleInputBuffer(std::move(moduleInputBuffer)), ModuleDocInputBuffer(std::move(moduleDocInputBuffer)), ModuleSourceInfoInputBuffer(std::move(moduleSourceInfoInputBuffer)) { @@ -1137,7 +1137,7 @@ ModuleFileSharedCore::ModuleFileSharedCore( info = validateControlBlock(cursor, scratch, {SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR}, - extInfo); + &extInfo); if (info.status != Status::Valid) { error(info.status); return; @@ -1145,7 +1145,11 @@ ModuleFileSharedCore::ModuleFileSharedCore( Name = info.name; TargetTriple = info.targetTriple; CompatibilityVersion = info.compatibilityVersion; - IsSIB = extInfo->isSIB(); + Bits.ArePrivateImportsEnabled = extInfo.arePrivateImportsEnabled(); + Bits.IsSIB = extInfo.isSIB(); + Bits.IsTestable = extInfo.isTestable(); + Bits.ResilienceStrategy = unsigned(extInfo.getResilienceStrategy()); + Bits.IsImplicitDynamicEnabled = extInfo.isImplicitDynamicEnabled(); MiscVersion = info.miscVersion; hasValidControlBlock = true; diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index 5991b92a108ed..9719425a44b9c 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -69,11 +69,6 @@ class ModuleFileSharedCore { /// The data blob containing all of the module's identifiers. StringRef IdentifierData; - /// Is this module file actually a .sib file? .sib files are serialized SIL at - /// arbitrary granularity and arbitrary stage; unlike serialized Swift - /// modules, which are assumed to contain canonical SIL for an entire module. - bool IsSIB = false; - // Full blob from the misc. version field of the metadata block. This should // include the version string of the compiler that built the module. StringRef MiscVersion; @@ -307,6 +302,21 @@ class ModuleFileSharedCore { /// Whether an error has been detected setting up this module file. unsigned HasError : 1; + /// Whether this module is `-enable-private-imports`. + unsigned ArePrivateImportsEnabled : 1; + + /// Whether this module file is actually a .sib file. + unsigned IsSIB: 1; + + /// Whether this module file is compiled with '-enable-testing'. + unsigned IsTestable : 1; + + /// Discriminator for resilience strategy. + unsigned ResilienceStrategy : 2; + + /// Whether this module is compiled with implicit dynamic. + unsigned IsImplicitDynamicEnabled: 1; + // Explicitly pad out to the next word boundary. unsigned : 0; } Bits = {}; @@ -327,7 +337,7 @@ class ModuleFileSharedCore { std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, bool isFramework, serialization::ValidationInfo &info, - serialization::ExtendedValidationInfo *extInfo); + serialization::ExtendedValidationInfo &extInfo); /// Change the status of the current module. Status error(Status issue) { @@ -456,7 +466,7 @@ class ModuleFileSharedCore { std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, bool isFramework, std::shared_ptr &theModule, - serialization::ExtendedValidationInfo *extInfo = nullptr) { + serialization::ExtendedValidationInfo &extInfo) { serialization::ValidationInfo info; auto *core = new ModuleFileSharedCore( std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 7ea7425824bf4..d9ea8061b2a6c 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -394,7 +394,7 @@ llvm::ErrorOr SerializedModuleLoaderBase::scanModuleFile( nullptr, nullptr, isFramework, loadedModuleFile, - &extInfo); + extInfo); // Map the set of dependencies over to the "module dependencies". auto dependencies = ModuleDependencies::forSwiftModule(modulePath.str(), isFramework); @@ -704,19 +704,19 @@ FileUnit *SerializedModuleLoaderBase::loadAST( std::move(moduleDocInputBuffer), std::move(moduleSourceInfoInputBuffer), isFramework, loadedModuleFileCore, - &extendedInfo); + extendedInfo); if (loadInfo.status == serialization::Status::Valid) { loadedModuleFile = std::make_unique(std::move(loadedModuleFileCore)); - M.setResilienceStrategy(extendedInfo.getResilienceStrategy()); + M.setResilienceStrategy(loadedModuleFile->getResilienceStrategy()); // We've loaded the file. Now try to bring it into the AST. auto fileUnit = new (Ctx) SerializedASTFile(M, *loadedModuleFile); - if (extendedInfo.isTestable()) + if (loadedModuleFile->isTestable()) M.setTestingEnabled(); - if (extendedInfo.arePrivateImportsEnabled()) + if (loadedModuleFile->arePrivateImportsEnabled()) M.setPrivateImportsEnabled(); - if (extendedInfo.isImplicitDynamicEnabled()) + if (loadedModuleFile->isImplicitDynamicEnabled()) M.setImplicitDynamicEnabled(); auto diagLocOrInvalid = diagLoc.getValueOr(SourceLoc()); From fae8f944b8aef3cb095189e6cf49c3fa1efbef60 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 2 Sep 2020 23:02:59 -0400 Subject: [PATCH 542/663] AST: Add 'hoisted' flag to Decl --- include/swift/AST/Decl.h | 21 +++++++++++++++++++-- include/swift/AST/SourceFile.h | 13 +++++++++++++ lib/AST/ASTDumper.cpp | 3 +++ lib/AST/Module.cpp | 4 ++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c9448731e3a85..4884cffe55837 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -284,7 +284,7 @@ class alignas(1 << DeclAlignInBits) Decl { protected: union { uint64_t OpaqueBits; - SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1, + SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1, Kind : bitmax(NumDeclKindBits,8), /// Whether this declaration is invalid. @@ -301,7 +301,13 @@ class alignas(1 << DeclAlignInBits) Decl { /// Whether this declaration was added to the surrounding /// DeclContext of an active #if config clause. - EscapedFromIfConfig : 1 + EscapedFromIfConfig : 1, + + /// Whether this declaration is syntactically scoped inside of + /// a local context, but should behave like a top-level + /// declaration for name lookup purposes. This is used by + /// lldb. + Hoisted : 1 ); SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+2+16, @@ -690,6 +696,7 @@ class alignas(1 << DeclAlignInBits) Decl { Bits.Decl.Implicit = false; Bits.Decl.FromClang = false; Bits.Decl.EscapedFromIfConfig = false; + Bits.Decl.Hoisted = false; } /// Get the Clang node associated with this declaration. @@ -837,6 +844,16 @@ class alignas(1 << DeclAlignInBits) Decl { /// Mark this declaration as implicit. void setImplicit(bool implicit = true) { Bits.Decl.Implicit = implicit; } + /// Determine whether this declaration is syntactically scoped inside of + /// a local context, but should behave like a top-level declaration + /// for name lookup purposes. This is used by lldb. + bool isHoisted() const { return Bits.Decl.Hoisted; } + + /// Set whether this declaration should be syntactically scoped inside + /// of a local context, but should behave like a top-level declaration, + /// but should behave like a top-level declaration. This is used by lldb. + void setHoisted(bool hoisted = true) { Bits.Decl.Hoisted = hoisted; } + public: bool escapedFromIfConfig() const { return Bits.Decl.EscapedFromIfConfig; diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index 6e303eef60cab..86af09971f60a 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -187,6 +187,10 @@ class SourceFile final : public FileUnit { /// have been removed, this can become an optional ArrayRef. Optional> Decls; + /// The list of hoisted declarations. See Decl::isHoisted(). + /// This is only used by lldb. + std::vector Hoisted; + using SeparatelyImportedOverlayMap = llvm::SmallDenseMap>; @@ -231,9 +235,18 @@ class SourceFile final : public FileUnit { Decls->insert(Decls->begin(), d); } + /// Add a hoisted declaration. See Decl::isHoisted(). + void addHoistedDecl(Decl *d) { + Hoisted.push_back(d); + } + /// Retrieves an immutable view of the list of top-level decls in this file. ArrayRef getTopLevelDecls() const; + /// Retrieves an immutable view of the list of hoisted decls in this file. + /// See Decl::isHoisted(). + ArrayRef getHoistedDecls() const; + /// Retrieves an immutable view of the top-level decls if they have already /// been parsed, or \c None if they haven't. Should only be used for dumping. Optional> getCachedTopLevelDecls() const { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index d454188f1a8e7..caf25cf5dada0 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -585,6 +585,9 @@ namespace { if (D->isImplicit()) PrintWithColorRAII(OS, DeclModifierColor) << " implicit"; + if (D->isHoisted()) + PrintWithColorRAII(OS, DeclModifierColor) << " hoisted"; + auto R = D->getSourceRange(); if (R.isValid()) { PrintWithColorRAII(OS, RangeColor) << " range="; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 3399d77f3aa7c..ba33830a6560d 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2342,6 +2342,10 @@ ArrayRef SourceFile::getTopLevelDecls() const { {}).TopLevelDecls; } +ArrayRef SourceFile::getHoistedDecls() const { + return Hoisted; +} + bool FileUnit::walk(ASTWalker &walker) { SmallVector Decls; getTopLevelDecls(Decls); From 4923aab2ea0cf9cca6b182e1cffef2fa1c4918b8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 00:18:23 -0400 Subject: [PATCH 543/663] AST: Add hoisted declarations to unqualified name lookup cache --- lib/AST/Module.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index ba33830a6560d..35fa382c742e4 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -312,6 +312,7 @@ SourceLookupCache::SourceLookupCache(const SourceFile &SF) { FrontendStatsTracer tracer(SF.getASTContext().Stats, "source-file-populate-cache"); addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false); + addToUnqualifiedLookupCache(SF.getHoistedDecls(), false); } SourceLookupCache::SourceLookupCache(const ModuleDecl &M) { @@ -322,8 +323,9 @@ SourceLookupCache::SourceLookupCache(const ModuleDecl &M) { addToUnqualifiedLookupCache(SFU->getTopLevelDecls(), false); continue; } - auto &SF = *cast(file); - addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false); + auto *SF = cast(file); + addToUnqualifiedLookupCache(SF->getTopLevelDecls(), false); + addToUnqualifiedLookupCache(SF->getHoistedDecls(), false); } } From 5d602dca0efff93a0ababb1697266491923c6e27 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 14:51:27 -0400 Subject: [PATCH 544/663] Sema: Visit hoisted ImportDecls in import resolution --- lib/Sema/ImportResolution.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 2ec7aacd2a964..c8ed785366efb 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -298,6 +298,8 @@ void swift::performImportResolution(SourceFile &SF) { // Resolve each import declaration. for (auto D : SF.getTopLevelDecls()) resolver.visit(D); + for (auto D : SF.getHoistedDecls()) + resolver.visit(D); SF.setImports(resolver.getFinishedImports()); From 5746322a0906f960511356d9c3e0ef4d097b7b31 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 14:53:34 -0400 Subject: [PATCH 545/663] Sema: Visit hoisted ExtensionDecls in extension binding --- lib/Sema/TypeChecker.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 1b4c38235c72b..f56b56339a4fa 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -215,11 +215,17 @@ void swift::bindExtensions(ModuleDecl &mod) { if (!SF) continue; - for (auto D : SF->getTopLevelDecls()) { + auto visitTopLevelDecl = [&](Decl *D) { if (auto ED = dyn_cast(D)) if (!tryBindExtension(ED)) - worklist.push_back(ED); - } + worklist.push_back(ED);; + }; + + for (auto *D : SF->getTopLevelDecls()) + visitTopLevelDecl(D); + + for (auto *D : SF->getHoistedDecls()) + visitTopLevelDecl(D); } // Phase 2 - repeatedly go through the worklist and attempt to bind each From b9cd6caa7299af244bba5c65cbc0de2c8839d05c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 14:51:39 -0400 Subject: [PATCH 546/663] SILGen: Emit hoisted declarations at the top level --- lib/SILGen/SILGen.cpp | 6 ++++++ lib/SILGen/SILGenStmt.cpp | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index ecd8482d96768..e8820020b3001 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1889,6 +1889,12 @@ class SILGenModuleRAII { SGM.visit(D); } + for (Decl *D : sf->getHoistedDecls()) { + FrontendStatsTracer StatsTracer(SGM.getASTContext().Stats, + "SILgen-decl", D); + SGM.visit(D); + } + for (TypeDecl *TD : sf->LocalTypeDecls) { FrontendStatsTracer StatsTracer(SGM.getASTContext().Stats, "SILgen-tydecl", TD); diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp index 9854969b1470f..0f30f1c4c15bb 100644 --- a/lib/SILGen/SILGenStmt.cpp +++ b/lib/SILGen/SILGenStmt.cpp @@ -346,7 +346,13 @@ void StmtEmitter::visitBraceStmt(BraceStmt *S) { } else if (auto *E = ESD.dyn_cast()) { SGF.emitIgnoredExpr(E); } else { - SGF.visit(ESD.get()); + auto *D = ESD.get(); + + // Hoisted declarations are emitted at the top level by emitSourceFile(). + if (D->isHoisted()) + continue; + + SGF.visit(D); } } } From 0bedd20ddd083d239dadc55c46b8f111cbd4a405 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 14:51:48 -0400 Subject: [PATCH 547/663] IRGen: Emit hoisted declarations at the top level --- lib/IRGen/GenDecl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 1ae4e85c3b477..5c7c205dd677b 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -449,13 +449,15 @@ void IRGenModule::emitSourceFile(SourceFile &SF) { // Emit types and other global decls. for (auto *decl : SF.getTopLevelDecls()) emitGlobalDecl(decl); + for (auto *decl : SF.getHoistedDecls()) + emitGlobalDecl(decl); for (auto *localDecl : SF.LocalTypeDecls) emitGlobalDecl(localDecl); for (auto *opaqueDecl : SF.getOpaqueReturnTypeDecls()) maybeEmitOpaqueTypeDecl(opaqueDecl); SF.collectLinkLibraries([this](LinkLibrary linkLib) { - this->addLinkLibrary(linkLib); + this->addLinkLibrary(linkLib); }); if (ObjCInterop) From f3e7963c0de735f2a76a392fc6d8f728bc8e52f3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 00:18:43 -0400 Subject: [PATCH 548/663] Parse: Mark declarations as hoisted in DebuggerContextChange Expression evaluation in lldb wraps the entire user-written expression in a new function body, which puts any new declarations written by the user in local context. There is a mechanism where declarations can get moved to the top level, if they're only valid at the top level (imports, extensions etc), or if the name of the declaration begins with '$'. This mechanism used to actually add the declaration to the SourceFile's TopLevelDecls list, which would break ASTScope invariants about source ranges being monotonically increasing and non-overlapping. Instead, we use the new 'hoisted' flag to mark the declarations as hoisted, which leaves them syntactically in their original location in the AST, but treats them as top level in SILGen and IRGen. Part of . --- include/swift/Parse/Parser.h | 14 +----- lib/Parse/ParseDecl.cpp | 95 +++++++++++++----------------------- 2 files changed, 35 insertions(+), 74 deletions(-) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 7f1b3ddba9249..18c69502936f9 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -125,9 +125,6 @@ class Parser { CodeCompletionCallbacks *CodeCompletion = nullptr; std::vector>> AnonClosureVars; - /// Tracks parsed decls that LLDB requires to be inserted at the top-level. - std::vector ContextSwitchedTopLevelDecls; - /// The current token hash, or \c None if the parser isn't computing a hash /// for the token stream. Optional CurrentTokenHash; @@ -146,7 +143,6 @@ class Parser { ArrayRef DisabledVars; Diag<> DisabledVarReason; - llvm::SmallPtrSet AlreadyHandledDecls; enum { /// InVarOrLetPattern has this value when not parsing a pattern. IVOLP_NotInVarOrLet, @@ -930,14 +926,8 @@ class Parser { void consumeDecl(ParserPosition BeginParserPosition, ParseDeclOptions Flags, bool IsTopLevel); - // When compiling for the Debugger, some Decl's need to be moved from the - // current scope. In which case although the Decl will be returned in the - // ParserResult, it should not be inserted into the Decl list for the current - // context. markWasHandled asserts that the Decl is already where it - // belongs, and declWasHandledAlready is used to check this assertion. - // To keep the handled decl array small, we remove the Decl when it is - // checked, so you can only call declWasAlreadyHandled once for a given - // decl. + /// FIXME: Remove this, it's vestigial. + llvm::SmallPtrSet AlreadyHandledDecls; void markWasHandled(Decl *D) { AlreadyHandledDecls.insert(D); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index ac374bee7e53b..32c7d78b54edb 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -60,15 +60,9 @@ namespace { /// file scope level so it will be set up correctly for this purpose. /// /// Creating an instance of this object will cause it to figure out - /// whether we are in the debugger function, whether it needs to swap + /// whether we are in the debugger function, and whether it needs to swap /// the Decl that is currently being parsed. - /// If you have created the object, instead of returning the result - /// with makeParserResult, use the object's fixupParserResult. If - /// no swap has occurred, these methods will work the same. - /// If the decl has been moved, then Parser::markWasHandled will be - /// called on the Decl, and you should call declWasHandledAlready - /// before you consume the Decl to see if you actually need to - /// consume it. + /// /// If you are making one of these objects to address issue 1, call /// the constructor that only takes a DeclKind, and it will be moved /// unconditionally. Otherwise pass in the Name and DeclKind and the @@ -76,32 +70,24 @@ namespace { class DebuggerContextChange { protected: Parser &P; - Identifier Name; - SourceFile *SF; Optional CC; + SourceFile *SF; public: - DebuggerContextChange (Parser &P) - : P(P), SF(nullptr) { + DebuggerContextChange(Parser &P) : P(P), SF(nullptr) { if (!inDebuggerContext()) return; - else - switchContext(); + + switchContext(); } - DebuggerContextChange (Parser &P, Identifier &Name, DeclKind Kind) - : P(P), Name(Name), SF(nullptr) { + DebuggerContextChange(Parser &P, Identifier Name, DeclKind Kind) + : P(P), SF(nullptr) { if (!inDebuggerContext()) return; - bool globalize = false; - - DebuggerClient *debug_client = getDebuggerClient(); - if (!debug_client) - return; - - globalize = debug_client->shouldGlobalize(Name, Kind); - - if (globalize) - switchContext(); + + if (auto *client = getDebuggerClient()) + if (client->shouldGlobalize(Name, Kind)) + switchContext(); } bool movedToTopLevel() { @@ -118,8 +104,10 @@ namespace { template ParserResult fixupParserResult(T *D) { - if (CC.hasValue()) { - swapDecl(D); + if (movedToTopLevel()) { + D->setHoisted(); + SF->addHoistedDecl(D); + getDebuggerClient()->didGlobalize(D); } return ParserResult(D); } @@ -127,10 +115,10 @@ namespace { template ParserResult fixupParserResult(ParserStatus Status, T *D) { - if (CC.hasValue() && !Status.isError()) { - // If there is an error, don't do our splicing trick, - // just return the Decl and the status for reporting. - swapDecl(D); + if (movedToTopLevel()) { + D->setHoisted(); + SF->addHoistedDecl(D); + getDebuggerClient()->didGlobalize(D); } return makeParserResult(Status, D); } @@ -140,13 +128,9 @@ namespace { ~DebuggerContextChange () {} protected: - DebuggerClient *getDebuggerClient() - { - ModuleDecl *PM = P.CurDeclContext->getParentModule(); - if (!PM) - return nullptr; - else - return PM->getDebugClient(); + DebuggerClient *getDebuggerClient() { + ModuleDecl *M = P.CurDeclContext->getParentModule(); + return M->getDebugClient(); } bool inDebuggerContext() { @@ -154,29 +138,19 @@ namespace { return false; if (!P.CurDeclContext) return false; - auto *func_decl = dyn_cast(P.CurDeclContext); - if (!func_decl) + auto *func = dyn_cast(P.CurDeclContext); + if (!func) return false; - - if (!func_decl->getAttrs().hasAttribute()) + + if (!func->getAttrs().hasAttribute()) return false; - + return true; } - void switchContext () { + void switchContext() { SF = P.CurDeclContext->getParentSourceFile(); - CC.emplace (P, SF); - } - - void swapDecl (Decl *D) - { - assert (SF); - DebuggerClient *debug_client = getDebuggerClient(); - assert (debug_client); - debug_client->didGlobalize(D); - P.ContextSwitchedTopLevelDecls.push_back(D); - P.markWasHandled(D); + CC.emplace(P, SF); } }; } // end anonymous namespace @@ -225,10 +199,6 @@ void Parser::parseTopLevel(SmallVectorImpl &decls) { } } - // First append any decls that LLDB requires be inserted at the top-level. - decls.append(ContextSwitchedTopLevelDecls.begin(), - ContextSwitchedTopLevelDecls.end()); - // Then append the top-level decls we parsed. for (auto item : items) { auto *decl = item.get(); @@ -7726,8 +7696,9 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags, SourceLoc precedenceGroupLoc = consumeToken(tok::kw_precedencegroup); DebuggerContextChange DCC (*this); - if (!CodeCompletion && !DCC.movedToTopLevel() && !(flags & PD_AllowTopLevel)) - { + if (!CodeCompletion && + !DCC.movedToTopLevel() && + !(flags & PD_AllowTopLevel)) { diagnose(precedenceGroupLoc, diag::decl_inner_scope); return nullptr; } From 5305c6f5087442571cdf4ba2b4e326640987e9cc Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 3 Sep 2020 21:18:16 +0100 Subject: [PATCH 549/663] Bring back `swift_once` context workaround in `Once.cpp` --- stdlib/public/runtime/Once.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index d77e9c002dfd2..c3752d4b171b5 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -55,7 +55,12 @@ void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), #ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME if (! *predicate) { *predicate = true; - fn(context); + // WebAssembly: hack: Swift compiler passes in a fn that doesn't take a parameter, + // which is invalid in WebAssembly. So swift_once casts the function. + // The correct way to fix this is to change + // SILGenModule::emitLazyGlobalInitializer + // but this is OK as a proof of concept. + ((void (*)())fn)(); } #elif defined(__APPLE__) dispatch_once_f(predicate, context, fn); @@ -64,4 +69,4 @@ void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), #else std::call_once(*predicate, [fn, context]() { fn(context); }); #endif -} \ No newline at end of file +} From 6a0a448b011ae9849bface121baae15d4617114e Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 3 Sep 2020 14:51:28 -0700 Subject: [PATCH 550/663] [Serialization] Remove extInfo param from ModuleFileSharedCore::load() Populated 'ExtendedValidationInfo' is not used at all. --- include/swift/Serialization/Validation.h | 5 ++--- lib/Serialization/ModuleFile.cpp | 4 +--- lib/Serialization/ModuleFileSharedCore.cpp | 4 ++-- lib/Serialization/ModuleFileSharedCore.h | 9 ++++----- lib/Serialization/SerializedModuleLoader.cpp | 11 +++-------- 5 files changed, 12 insertions(+), 21 deletions(-) diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h index f0e84e7d7676e..ab2aed06d0079 100644 --- a/include/swift/Serialization/Validation.h +++ b/include/swift/Serialization/Validation.h @@ -177,9 +177,8 @@ ValidationInfo validateSerializedAST( /// - \p ModuleName is the name used to refer to the module in diagnostics. void diagnoseSerializedASTLoadFailure( ASTContext &Ctx, SourceLoc diagLoc, const ValidationInfo &loadInfo, - const ExtendedValidationInfo &extendedInfo, StringRef moduleBufferID, - StringRef moduleDocBufferID, ModuleFile *loadedModuleFile, - Identifier ModuleName); + StringRef moduleBufferID, StringRef moduleDocBufferID, + ModuleFile *loadedModuleFile, Identifier ModuleName); } // end namespace serialization } // end namespace swift diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 3bb3eec65fc55..80b4b9d57e857 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -349,15 +349,13 @@ ModuleFile::getModuleName(ASTContext &Ctx, StringRef modulePath, llvm::MemoryBuffer::getMemBuffer(llvm::MemoryBufferRef(*moduleBuf.get()), /*RequiresNullTerminator=*/false); std::shared_ptr loadedModuleFile; - ExtendedValidationInfo ExtInfo; bool isFramework = false; serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(modulePath.str(), std::move(newBuf), nullptr, nullptr, - /*isFramework*/isFramework, loadedModuleFile, - ExtInfo); + /*isFramework*/isFramework, loadedModuleFile); Name = loadedModuleFile->Name.str(); return std::move(moduleBuf.get()); } diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index 1f08740a8a50a..a2032f6715d0b 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -1087,8 +1087,7 @@ ModuleFileSharedCore::ModuleFileSharedCore( std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, - bool isFramework, serialization::ValidationInfo &info, - serialization::ExtendedValidationInfo &extInfo) + bool isFramework, serialization::ValidationInfo &info) : ModuleInputBuffer(std::move(moduleInputBuffer)), ModuleDocInputBuffer(std::move(moduleDocInputBuffer)), ModuleSourceInfoInputBuffer(std::move(moduleSourceInfoInputBuffer)) { @@ -1134,6 +1133,7 @@ ModuleFileSharedCore::ModuleFileSharedCore( return; } + ExtendedValidationInfo extInfo; info = validateControlBlock(cursor, scratch, {SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR}, diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index 9719425a44b9c..2caa4a3920487 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -336,8 +336,7 @@ class ModuleFileSharedCore { ModuleFileSharedCore(std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, - bool isFramework, serialization::ValidationInfo &info, - serialization::ExtendedValidationInfo &extInfo); + bool isFramework, serialization::ValidationInfo &info); /// Change the status of the current module. Status error(Status issue) { @@ -465,12 +464,12 @@ class ModuleFileSharedCore { std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, std::unique_ptr moduleSourceInfoInputBuffer, - bool isFramework, std::shared_ptr &theModule, - serialization::ExtendedValidationInfo &extInfo) { + bool isFramework, + std::shared_ptr &theModule) { serialization::ValidationInfo info; auto *core = new ModuleFileSharedCore( std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), - std::move(moduleSourceInfoInputBuffer), isFramework, info, extInfo); + std::move(moduleSourceInfoInputBuffer), isFramework, info); if (!moduleInterfacePath.empty()) { ArrayRef path; core->allocateBuffer(path, moduleInterfacePath); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index d9ea8061b2a6c..33c84e84cdbf4 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -387,14 +387,12 @@ llvm::ErrorOr SerializedModuleLoaderBase::scanModuleFile( // Load the module file without validation. std::shared_ptr loadedModuleFile; bool isFramework = false; - serialization::ExtendedValidationInfo extInfo; serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(modulePath.str(), std::move(moduleBuf.get()), nullptr, nullptr, - isFramework, loadedModuleFile, - extInfo); + isFramework, loadedModuleFile); // Map the set of dependencies over to the "module dependencies". auto dependencies = ModuleDependencies::forSwiftModule(modulePath.str(), isFramework); @@ -695,7 +693,6 @@ FileUnit *SerializedModuleLoaderBase::loadAST( return nullptr; } - serialization::ExtendedValidationInfo extendedInfo; std::unique_ptr loadedModuleFile; std::shared_ptr loadedModuleFileCore; serialization::ValidationInfo loadInfo = @@ -703,8 +700,7 @@ FileUnit *SerializedModuleLoaderBase::loadAST( std::move(moduleInputBuffer), std::move(moduleDocInputBuffer), std::move(moduleSourceInfoInputBuffer), - isFramework, loadedModuleFileCore, - extendedInfo); + isFramework, loadedModuleFileCore); if (loadInfo.status == serialization::Status::Valid) { loadedModuleFile = std::make_unique(std::move(loadedModuleFileCore)); @@ -744,7 +740,7 @@ FileUnit *SerializedModuleLoaderBase::loadAST( if (diagLoc) serialization::diagnoseSerializedASTLoadFailure( - Ctx, *diagLoc, loadInfo, extendedInfo, moduleBufferID, + Ctx, *diagLoc, loadInfo, moduleBufferID, moduleDocBufferID, loadedModuleFile.get(), M.getName()); // Even though the module failed to load, it's possible its contents include @@ -761,7 +757,6 @@ FileUnit *SerializedModuleLoaderBase::loadAST( void swift::serialization::diagnoseSerializedASTLoadFailure( ASTContext &Ctx, SourceLoc diagLoc, const serialization::ValidationInfo &loadInfo, - const serialization::ExtendedValidationInfo &extendedInfo, StringRef moduleBufferID, StringRef moduleDocBufferID, ModuleFile *loadedModuleFile, Identifier ModuleName) { auto diagnoseDifferentLanguageVersion = [&](StringRef shortVersion) -> bool { From a92e9b3288254628f2492d308a3d6ff0c90b6544 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 3 Sep 2020 18:50:32 +0000 Subject: [PATCH 551/663] SILOptimizer: make vtable pruning less aggressive A class which is marked as internal or public can be visible outside of the current file, where the use of the VWT indirectly is possible. If the VWT is modified and inlined, it is possible that the offsets will no longer match resulting in an invalid dispatch. Limit the pass to when WMO is enabled or the type is private in non-WMO cases. --- lib/SILOptimizer/Transforms/PruneVTables.cpp | 10 ++++++++-- test/SILOptimizer/prune-vtables.sil | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/SILOptimizer/Transforms/PruneVTables.cpp b/lib/SILOptimizer/Transforms/PruneVTables.cpp index 18543900f921e..f1c37c892c8c9 100644 --- a/lib/SILOptimizer/Transforms/PruneVTables.cpp +++ b/lib/SILOptimizer/Transforms/PruneVTables.cpp @@ -27,10 +27,16 @@ using namespace swift; namespace { class PruneVTables : public SILModuleTransform { - void runOnVTable(SILModule *M, - SILVTable *vtable) { + void runOnVTable(SILModule *M, SILVTable *vtable) { LLVM_DEBUG(llvm::dbgs() << "PruneVTables inspecting table:\n"; vtable->print(llvm::dbgs())); + if (!M->isWholeModule() && + vtable->getClass()->getEffectiveAccess() >= AccessLevel::FilePrivate) { + LLVM_DEBUG(llvm::dbgs() << "Ignoring visible table: "; + vtable->print(llvm::dbgs())); + return; + } + for (auto &entry : vtable->getMutableEntries()) { // We don't need to worry about entries that are overridden, diff --git a/test/SILOptimizer/prune-vtables.sil b/test/SILOptimizer/prune-vtables.sil index d72af0b338b10..633dc9e53bf5a 100644 --- a/test/SILOptimizer/prune-vtables.sil +++ b/test/SILOptimizer/prune-vtables.sil @@ -14,9 +14,9 @@ sil @PrivateA_yesOverrides : $@convention(method) (@guaranteed PrivateA) -> () sil @PrivateA_isFinal : $@convention(method) (@guaranteed PrivateA) -> () // NOWMO-LABEL: sil_vtable PrivateA { -// NOWMO: #PrivateA.noOverrides{{.*}} [nonoverridden] +// NOWMO: #PrivateA.noOverrides{{[^[]]*}} // NOWMO-NOT: #PrivateA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PrivateA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PrivateA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PrivateA { // WMO: #PrivateA.noOverrides{{.*}} [nonoverridden] @@ -35,9 +35,9 @@ private class PrivateB: PrivateA { sil @PrivateB_yesOverrides : $@convention(method) (@guaranteed PrivateB) -> () // NOWMO-LABEL: sil_vtable PrivateB { -// NOWMO: #PrivateA.noOverrides{{.*}} [nonoverridden] +// NOWMO: #PrivateA.noOverrides{{[^[]]*}} // NOWMO-NOT: #PrivateA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PrivateA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PrivateA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PrivateB { // WMO: #PrivateA.noOverrides{{.*}} [nonoverridden] @@ -62,7 +62,7 @@ sil @InternalA_isFinal : $@convention(method) (@guaranteed InternalA) -> () // NOWMO-LABEL: sil_vtable InternalA { // NOWMO-NOT: #InternalA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #InternalA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #InternalA.isFinal{{.*}} [nonoverridden] +// NOWMO: #InternalA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable InternalA { // WMO: #InternalA.noOverrides{{.*}} [nonoverridden] @@ -83,7 +83,7 @@ sil @InternalB_yesOverrides : $@convention(method) (@guaranteed InternalB) -> () // NOWMO-LABEL: sil_vtable InternalB { // NOWMO-NOT: #InternalA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #InternalA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #InternalA.isFinal{{.*}} [nonoverridden] +// NOWMO: #InternalA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable InternalB { // WMO: #InternalA.noOverrides{{.*}} [nonoverridden] @@ -108,7 +108,7 @@ sil @PublicA_isFinal : $@convention(method) (@guaranteed PublicA) -> () // NOWMO-LABEL: sil_vtable PublicA { // NOWMO-NOT: #PublicA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #PublicA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PublicA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PublicA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PublicA { // WMO: #PublicA.noOverrides{{.*}} [nonoverridden] @@ -129,7 +129,7 @@ sil @PublicB_yesOverrides : $@convention(method) (@guaranteed PublicB) -> () // NOWMO-LABEL: sil_vtable PublicB { // NOWMO-NOT: #PublicA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #PublicA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #PublicA.isFinal{{.*}} [nonoverridden] +// NOWMO: #PublicA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable PublicB { // WMO: #PublicA.noOverrides{{.*}} [nonoverridden] @@ -154,7 +154,7 @@ sil @OpenA_isFinal : $@convention(method) (@guaranteed OpenA) -> () // NOWMO-LABEL: sil_vtable OpenA { // NOWMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #OpenA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #OpenA.isFinal{{.*}} [nonoverridden] +// NOWMO: #OpenA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable OpenA { // WMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] @@ -175,7 +175,7 @@ sil @OpenB_yesOverrides : $@convention(method) (@guaranteed OpenB) -> () // NOWMO-LABEL: sil_vtable OpenB { // NOWMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] // NOWMO-NOT: #OpenA.yesOverrides{{.*}} [nonoverridden] -// NOWMO: #OpenA.isFinal{{.*}} [nonoverridden] +// NOWMO: #OpenA.isFinal{{[^[]]*}} // WMO-LABEL: sil_vtable OpenB { // WMO-NOT: #OpenA.noOverrides{{.*}} [nonoverridden] From b73330b113a900a83e14420f76e7c91b7e694a76 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Thu, 3 Sep 2020 15:56:00 -0700 Subject: [PATCH 552/663] [DynamicCast] Rework existential casting discussion A previous PR collected the various existential types into a single section of the document. This PR takes advantage of that structure to clarify the discussion of existential and protocol casting: * Adds a general discussion of existential casting * Introduces the "strong existential invariant" and "weak existential invariant" that are common to all existential types * Makes a more precise distinction between protocols and existential types This last point involves a number of careful wording nuances based on the following: * A "protocol" is a syntactic construct defining a collection of requirements and default implementations (the latter via "protocol extensions") * Some protocol definitions (those without associated types or `Self` references) have an associated "protocol witness" existential type * A protocol witness existential type has the same name as the protocol definition from which it is derived but they are conceptually different notions * Existential types such as `Any`, `AnyObject`, and `Error` are not protocols -- for example, they cannot be extended. * `AnyHashable` is a type-erased container type but is not an existential. It does however behave like an existential for casting purposes. --- docs/DynamicCasting.md | 70 ++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md index 95568d12119bd..466666b7173b2 100644 --- a/docs/DynamicCasting.md +++ b/docs/DynamicCasting.md @@ -308,6 +308,26 @@ Note that it is _not_ sufficient for argument and return types to be castable; t Conceptually, an "existential type" is an opaque wrapper that carries a type and an instance of that type. The various existential types differ in what kinds of types they can hold (for example, `AnyObject` can only hold reference types) and in the capabilities exposed by the container (`AnyHashable` exposes equality testing and hashing). +The key invariant for existential types `E` is the following: +* Strong existential invariant: If `t` is any instance, `U` is any type, and `t is E` then `(t as! E) as? U` produces the same result as `t as? U` + +Intuitively, this simply says that if you can put an instance `t` into an existential `E`, then you can take it back out again via casting. +For Equatable types, this implies that the results of the two operations here are equal to each other when they succeed. +It also implies that if either of these `as?` casts fails, so will the other. + +`AnyObject` and `AnyHashable` do not fully satisfy the strong invariant described above. Instead, they satisfy the following weaker version: +* Weak existential invariant: If `t` is any instance, `U` is any type, and both `t is U` and `t is E`, then `(t as! E) as? U` produces the same result as `t as? U` + +### Objective-C Interactions + +The difference between the strong and weak existential invariants comes about because casting to `AnyObject` or `AnyHashable` can trigger Objective-C bridging conversions. +The result of these conversions may support casts that the original type did not. +As a result, `(t as! E)` may be castable to `U` even if `t` alone is not directly castable. + +One example of this is Foundation's `NSNumber` type which conditionally bridges to several Swift numeric types. +As a result, when Foundation is in scope, `Int(7) is Double == false` but `(Int(7) as! AnyObject) is Double == true`. +In general, the ability to add new bridging behaviors from a single type to several distinct types implies that Swift casting cannot be transitive. + ### Any Any Swift instance can be cast to the type `Any`. @@ -318,14 +338,7 @@ Invariants * If `t` is any instance, then `t is Any == true` * If `t` is any instance, `t as! Any` always succeeds * For every type `T` (including protocol types), `T.self is Any.Type` -* If `t` is any instance and `U` is any `Equatable` type, then `t as? U == (t as! Any) as? U`. - -This last invariant deserves some explanation, as a similar pattern appears repeatedly throughout this document. -In essence, this invariant just says that putting something into an "Any box" (`t as! Any`) and taking it out again (`as? U`) does not change the result. -The requirement that `U` be `Equatable` is a technical necessity for using `==` in this statement. - -Note that in many cases, we've shortened such invariants to the form `t is U == (t as! Any) is U`. -Using `is` here simply avoids the technical necessity that `U` be `Equatable` but except where explicitly called out, the intention in every case is that such casting does not change the value. +* Strong existential invariant: If `t` is any instance and `U` is any type, then `(t as! Any) as? U` produces the same result as `t as? U`. ### AnyObject @@ -334,49 +347,44 @@ Any class, enum, struct, tuple, function, metatype, or existential metatype inst XXX TODO The runtime logic has code to cast protocol types to `AnyObject` only if they are compatible with `__SwiftValue`. What is the practical effect of this logic? Does it mean that casting a protocol type to `AnyObject` will sometimes unwrap (if the protocol is incompatible) and sometimes not? What protocols are affected by this? The contents of an `AnyObject` container can be accessed by casting to another type: -* If `t` is any instance, `U` is any type, `t is AnyObject` and `t is U`, then `(t as! AnyObject) is U`. +* Weak existential invariant: If `t` is any instance, `U` is any type, `t is AnyObject`, and `t is U`, then `(t as! AnyObject) as? U` will produce the same result as `t as? U` Implementation Note: `AnyObject` is represented in memory as a pointer to a refcounted object. The dynamic type of the object can be recovered from the "isa" field of the object. The optional form `AnyObject?` is the same except that it allows null. Reference types (class, metatype, or existential metatype instances) can be directly assigned to an `AnyObject` without any conversion. For non-reference types -- including struct, enum, and tuple types -- the casting logic will first look for an `_ObjectiveCBridgeable` conformance that it can use to convert the source into a tailored reference type. If that fails, the value will be copied into an opaque `_SwiftValue` container. (See "The _ObjectiveCBridgeable Protocol" below for more details.) -### Objective-C Interactions - -Note the invariant above cannot be an equality because Objective-C bridging allows libraries to introduce new relationships that can alter the behavior of seemingly-unrelated casts. -One example of this is Foundation's `NSNumber` type which conditionally bridges to several Swift numeric types. -As a result, when Foundation is in scope, `Int(7) is Double == false` but `(Int(7) as! AnyObject) is Double == true`. -In general, the ability to add new bridging behaviors from a single type to several distinct types implies that Swift casting cannot be transitive. - ### Error (SE-0112) -Although the Error protocol is specially handled by the Swift compiler and runtime (as detailed in [SE-0112](https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md)), it behaves like an ordinary protocol type for casting purposes. +The Error type behaves like an ordinary existential type for casting purposes. (See "Note: 'Self-conforming' protocols" below for additional details relevant to the Error protocol.) ### AnyHashable (SE-0131) For casting purposes, `AnyHashable` behaves like an existential type. +It satisfies the weak existential invariant above. However, note that `AnyHashable` does not act like an existential for other purposes. For example, it's metatype is named `AnyHashable.Type` and it does not have an existential metatype. ### Protocol Witness types -Caveat: -Protocols that have `associatedtype` properties or which make use of the `Self` typealias cannot be used as independent types. -As such, the discussion below does not apply to them. +Any protocol definition (except those that include an `associatedtype` property or which makes use of the `Self` typealias) has an associated existential type named after the protocol. -Any Swift instance of a concrete type `T` can be cast to `P` iff `T` conforms to `P`. -The result is a "protocol witness" instance that provides access only to those methods and properties defined on `P`. +Specifically, assume you have a protocol definition +``` +protocol P {} +``` + +As a result of this definition, there is an existential type (also called `P`). +This existential type is also known as a "protocol witness" type since it exposes exactly the capabilities that are defined by the protocol. Other capabilities of the type `T` are not accessible from a `P` instance. +Any Swift instance of a concrete type `T` can be cast to the type `P` iff `T` conforms to the protocol `P`. The contents of a protocol witness can be accessed by casting to some other appropriate type: -* For any protocol `P`, instance `t`, and type `U`, if `t is P`, then `t as? U == (t as! P) as? U` - -XXX TODO: The invariant above does not apply to AnyObject, AnyHashable. -Does it suffice to explicitly exclude those two, or do other protocols share that behavior? The alternative would seem to be to change the equality here into an implication. +* Strong existential Invariant: For any protocol `P`, instance `t`, and type `U`, if `t is P`, then `t as? U` produces the same result as `(t as! P) as? U` -In addition to the protocol witness type, every Swift protocol `P` implicitly defines two other types: +In addition to the protocol witness type `P`, every Swift protocol `P` implicitly defines two other types: `P.Protocol` is the "protocol metatype", the type of `P.self`. `P.Type` is the "protocol existential metatype". These are described in more detail below. @@ -422,9 +430,11 @@ S.svar // Shorthand for S.self.svar ``` For most Swift types, the metatype of `T` is named `T.Type`. -However, in two cases the metatype has a different name: +However, in the following cases the metatype has a different name: * For a nominal protocol type `P`, the metatype is named `P.Protocol` -* For a type bound to a generic variable `G`, the metatype is named `G.Type` _even if `G` is bound to a protocol type_. Specifically, if `G` is bound to the nominal protocol type `P`, then `G.Type` is another name for the metatype `P.Protocol`, and hence `G.Type.self == P.Protocol.self`. +* For non-protocol existential types `E`, the metatype is also named `E.Protocol`. For example, `Any.Protocol`, `AnyObject.Protocol`, and `Error.Protocol`. +* For a type bound to a generic variable `G`, the metatype is named `G.Type` _even if `G` is bound to a protocol or existential type_. Specifically, if `G` is bound to the nominal protocol type `P`, then `G.Type` is another name for the metatype `P.Protocol`, and hence `G.Type.self == P.Protocol.self`. +* As explained above, although `AnyHashable` behaves like an existential type in some respects, its metatype is called `AnyHashable.Type`. Example: ``` @@ -456,7 +466,7 @@ Invariants * For a nominal non-protocol type `T`, `T.self is T.Type` * For a nominal protocol type `P`, `P.self is P.Protocol` * `P.Protocol` is a singleton: `T.self is P.Protocol` iff `T` is exactly `P` -* A non-protocol type `T` conforms to a protocol `P` iff `T.self is P.Type` +* A non-protocol type `T` conforms to a protocol `P` iff `T.self is P.Type` (If `T` is a protocol type, see "Self conforming existential types" below for details.) * `T` is a subtype of a non-protocol type `U` iff `T.self is U.Type` * Subtypes define metatype subtypes: if `T` and `U` are non-protocol types, `T.self is U.Type == T.Type.self is U.Type.Type` * Subtypes define metatype subtypes: if `T` is a non-protocol type and `P` is a protocol type, `T.self is P.Protocol == T.Type.self is P.Protocol.Type` From 354440402f4f5d6d25f18bd775f9719b361481cf Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Fri, 28 Aug 2020 02:12:25 +0200 Subject: [PATCH 553/663] [Localization] Create swift-def-to-yaml-converter tool --- localization/CMakeLists.txt | 3 + localization/diagnostics/en.yaml | 8321 ----------------- tools/CMakeLists.txt | 1 + .../CMakeLists.txt | 8 + .../swift-def-to-yaml-converter.cpp | 94 + unittests/CMakeLists.txt | 1 + unittests/DefToYAMLConverter/CMakeLists.txt | 9 + .../DefToYAMLConverterTest.cpp | 60 + 8 files changed, 176 insertions(+), 8321 deletions(-) delete mode 100644 localization/diagnostics/en.yaml create mode 100644 tools/swift-def-to-yaml-converter/CMakeLists.txt create mode 100644 tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp create mode 100644 unittests/DefToYAMLConverter/CMakeLists.txt create mode 100644 unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index 6a4ac7b0351fa..b880dd9460f89 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -3,6 +3,9 @@ add_custom_target(diagnostic-database) add_custom_command(TARGET diagnostic-database COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/ ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ + COMMAND + "${SWIFT_NATIVE_SWIFT_TOOLS_PATH}/swift-def-to-yaml-converter" + --output-directory ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ COMMAND "${SWIFT_NATIVE_SWIFT_TOOLS_PATH}/swift-serialize-diagnostics" --input-file-path ${CMAKE_BINARY_DIR}/share/swift/diagnostics/en.yaml diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml deleted file mode 100644 index d8b545c646460..0000000000000 --- a/localization/diagnostics/en.yaml +++ /dev/null @@ -1,8321 +0,0 @@ -#===--- en.yaml - Localized diagnostic messages for English ---*- YAML -*-===# -# -# This source file is part of the Swift.org open source project -# -# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -# Licensed under Apache License v2.0 with Runtime Library Exception -# -# See https://swift.org/LICENSE.txt for license information -# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -# -#===----------------------------------------------------------------------===# -# -# This file defines the diagnostic messages for the English language. -# Each diagnostic is described in the following format: -# - id: -# msg: "" -# -# The diagnostic message should be in double quotes and in one line, that -# means we will break the 80 characters line limit rule. That's mainly -# because currently `llvm::YAMLParser` doesn't support literal string -# folding, therefore we can't use YAML block scalars i.e. `>-`. -# -#===----------------------------------------------------------------------===# - -- id: invalid_diagnostic - msg: "INTERNAL ERROR: this diagnostic should not be produced" - -- id: not_implemented - msg: "INTERNAL ERROR: feature not implemented: %0" - -- id: error_opening_output - msg: "error opening '%0' for output: %1" - -- id: cannot_find_group_info_file - msg: "cannot find group info file at path: '%0'" - -- id: cannot_parse_group_info_file - msg: "cannot parse group info file at path: '%0'" - -- id: error_no_group_info - msg: "no group info found for file: '%0'" - -- id: previous_decldef - msg: "previous definition of %0 is here" - -- id: brace_stmt_suggest_do - msg: "did you mean to use a 'do' statement?" - -- id: while_parsing_as_left_angle_bracket - msg: "while parsing this '<' as a type parameter bracket" - -- id: remark_max_determinism_overriding - msg: "SWIFTC_MAXIMUM_DETERMINISM overriding %0" - -- id: super_not_in_class_method - msg: "'super' cannot be used outside of class members" - -- id: class_func_not_in_class - msg: "class methods are only allowed within classes; use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 method" - -- id: class_var_not_in_class - msg: "class properties are only allowed within classes; use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 property" - -- id: class_subscript_not_in_class - msg: "class subscripts are only allowed within classes; use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 subscript" - -- id: func_decl_without_brace - msg: "expected '{' in body of function declaration" - -- id: convert_let_to_var - msg: "change 'let' to 'var' to make it mutable" - -- id: note_typo_candidate - msg: "did you mean '%0'?" - -- id: profile_read_error - msg: "failed to load profile data '%0': '%1'" - -- id: protocol_extension_redundant_requirement - msg: "requirement of '%1' to '%2' is redundant in an extension of '%0'" - -- id: attr_only_on_parameters - msg: "'%0' may only be used on parameters" - -- id: function_type_no_parens - msg: "single argument function types require parentheses" - -- id: error_underlying_module_not_found - msg: "underlying Objective-C module %0 not found" - -- id: generic_signature_not_minimal - msg: "generic requirement '%0' is redundant in %1" - -- id: generic_signature_not_valid - msg: "generic signature %0 is invalid" - -- id: generic_signature_not_equal - msg: "generic signature %0 is not equal to new signature %1" - -- id: sdk_node_unrecognized_key - msg: "unrecognized key '%0' in SDK node" - -- id: sdk_node_unrecognized_node_kind - msg: "unrecognized SDK node kind '%0'" - -- id: sdk_node_unrecognized_type_attr_kind - msg: "unrecognized type attribute '%0' in SDK node" - -- id: sdk_node_unrecognized_decl_attr_kind - msg: "unrecognized declaration attribute '%0' in SDK node" - -- id: sdk_node_unrecognized_decl_kind - msg: "unrecognized declaration kind '%0' in SDK node" - -- id: sdk_node_unrecognized_accessor_kind - msg: "unrecognized accessor kind '%0' in SDK node" - -- id: source_location_creates_file_id_conflicts - msg: "'#sourceLocation' directive produces '#fileID' string of '%0', which conflicts with '#fileID' strings produced by other paths in the module" - -- id: fixit_correct_source_location_file - msg: "change file in '#sourceLocation' to '%0'" - -- id: error_two_files_same_name - msg: "filename \"%0\" used twice: '%1' and '%2'" - -- id: note_explain_two_files_same_name - msg: "filenames are used to distinguish private declarations with the same name" - -- id: circular_reference - msg: "circular reference" - -- id: circular_reference_through - msg: "through reference here" - -- id: circular_class_inheritance - msg: "%0 inherits from itself" - -- id: circular_enum_inheritance - msg: "%0 has a raw type that depends on itself" - -- id: circular_protocol_def - msg: "protocol %0 refines itself" - -- id: kind_declname_declared_here - msg: "%0 %1 declared here" - -- id: warn_property_wrapper_module_scope - msg: "ignoring associated type %0 in favor of module-scoped property wrapper %0; please qualify the reference with %1" - -- id: circular_type_resolution_note - msg: "while resolving type %0" - -- id: cannot_load_swiftoverlay_file - msg: "cannot load cross-import overlay for '%0' and '%1': %2 (declared by '%3')" - -- id: cannot_list_swiftcrossimport_dir - msg: "cannot list cross-import overlays for '%0': %1 (declared in '%2')" - -- id: cross_imported_by_both_modules - msg: "modules %0 and %1 both declare module %2 as a cross-import overlay, which may cause paradoxical behavior when looking up names in them; please report this bug to the maintainers of these modules" - -- id: scanner_find_cycle - msg: "dependency scanner detected dependency cycle: '%0'" - -- id: opening_brace - msg: "to match this opening '{'" - -- id: opening_bracket - msg: "to match this opening '['" - -- id: opening_paren - msg: "to match this opening '('" - -- id: opening_angle - msg: "to match this opening '<'" - -- id: extra_rbrace - msg: "extraneous '}' at top level" - -- id: structure_overflow - msg: "structure nesting level exceeded maximum of %0" - -- id: expected_close_to_if_directive - msg: "expected #else or #endif at end of conditional compilation block" - -- id: expected_close_after_else_directive - msg: "further conditions after #else are unreachable" - -- id: unexpected_conditional_compilation_block_terminator - msg: "unexpected conditional compilation block terminator" - -- id: incomplete_conditional_compilation_directive - msg: "incomplete condition in conditional compilation directive" - -- id: extra_tokens_conditional_compilation_directive - msg: "extra tokens following conditional compilation directive" - -- id: unexpected_rbrace_in_conditional_compilation_block - msg: "unexpected '}' in conditional compilation block" - -- id: unexpected_if_following_else_compilation_directive - msg: "unexpected 'if' keyword following '#else' conditional compilation directive; did you mean '#elseif'?" - -- id: pound_diagnostic_expected_string - msg: "expected string literal in %select{#warning|#error}0 directive" - -- id: pound_diagnostic_expected - msg: "expected '%0' in %select{#warning|#error}1 directive" - -- id: pound_diagnostic_expected_parens - msg: "%select{#warning|#error}0 directive requires parentheses" - -- id: pound_diagnostic_interpolation - msg: "string interpolation is not allowed in %select{#warning|#error}0 directives" - -- id: extra_tokens_pound_diagnostic_directive - msg: "extra tokens following %select{#warning|#error}0 directive" - -- id: sourceLocation_expected - msg: "expected '%0' in #sourceLocation directive" - -- id: unexpected_line_directive - msg: "parameterless closing #sourceLocation() directive without prior opening #sourceLocation(file:,line:) directive" - -- id: expected_line_directive_number - msg: "expected starting line number for #sourceLocation directive" - -- id: expected_line_directive_name - msg: "expected filename string literal for #sourceLocation directive" - -- id: extra_tokens_line_directive - msg: "extra tokens at the end of #sourceLocation directive" - -- id: line_directive_line_zero - msg: "the line number needs to be greater than zero" - -- id: escaped_parameter_name - msg: "keyword '%0' does not need to be escaped in argument list" - -- id: forbidden_interpolated_string - msg: "%0 cannot be an interpolated string literal" - -- id: forbidden_extended_escaping_string - msg: "%0 cannot be an extended escaping string literal" - -- id: lex_nul_character - msg: "nul character embedded in middle of file" - -- id: lex_utf16_bom_marker - msg: "input files must be encoded as UTF-8 instead of UTF-16" - -- id: lex_hashbang_not_allowed - msg: "hashbang line is allowed only in the main file" - -- id: lex_unprintable_ascii_character - msg: "unprintable ASCII character found in source file" - -- id: lex_invalid_utf8 - msg: "invalid UTF-8 found in source file" - -- id: lex_single_quote_string - msg: "single-quoted string literal found, use '\"'" - -- id: lex_invalid_curly_quote - msg: "unicode curly quote found, replace with '\"'" - -- id: lex_confusable_character - msg: "unicode character '%0' (%1) looks similar to '%2' (%3); did you mean to use '%2' (%3)?" - -- id: lex_nonbreaking_space - msg: "non-breaking space (U+00A0) used instead of regular space" - -- id: lex_unterminated_block_comment - msg: "unterminated '/*' comment" - -- id: lex_comment_start - msg: "comment started here" - -- id: lex_unterminated_string - msg: "unterminated string literal" - -- id: lex_invalid_escape - msg: "invalid escape sequence in literal" - -- id: lex_invalid_u_escape - msg: "\\u{...} escape sequence expects between 1 and 8 hex digits" - -- id: lex_invalid_u_escape_rbrace - msg: "expected '}' in \\u{...} escape sequence" - -- id: lex_invalid_escape_delimiter - msg: "too many '#' characters in delimited escape" - -- id: lex_invalid_closing_delimiter - msg: "too many '#' characters in closing delimiter" - -- id: lex_invalid_unicode_scalar - msg: "invalid unicode scalar" - -- id: lex_unicode_escape_braces - msg: "expected hexadecimal code in braces after unicode escape" - -- id: lex_illegal_multiline_string_start - msg: "multi-line string literal content must begin on a new line" - -- id: lex_illegal_multiline_string_end - msg: "multi-line string literal closing delimiter must begin on a new line" - -- id: lex_multiline_string_indent_inconsistent - msg: "%select{unexpected space in|unexpected tab in|insufficient}2 indentation of %select{line|next %1 lines}0 in multi-line string literal" - -- id: lex_multiline_string_indent_should_match_here - msg: "should match %select{space|tab}0 here" - -- id: lex_multiline_string_indent_change_line - msg: "change indentation of %select{this line|these lines}0 to match closing delimiter" - -- id: lex_escaped_newline_at_lastline - msg: "escaped newline at the last line is not allowed" - -- id: lex_invalid_character - msg: "invalid character in source file" - -- id: lex_invalid_identifier_start_character - msg: "an identifier cannot begin with this character" - -- id: lex_expected_digit_in_fp_exponent - msg: "expected a digit in floating point exponent" - -- id: lex_invalid_digit_in_fp_exponent - msg: "'%0' is not a valid %select{digit|first character}1 in floating point exponent" - -- id: lex_invalid_digit_in_int_literal - msg: "'%0' is not a valid %select{binary digit (0 or 1)|octal digit (0-7)|digit|hexadecimal digit (0-9, A-F)}1 in integer literal" - -- id: lex_expected_binary_exponent_in_hex_float_literal - msg: "hexadecimal floating point literal must end with an exponent" - -- id: lex_unexpected_block_comment_end - msg: "unexpected end of block comment" - -- id: lex_unary_equal - msg: "'=' must have consistent whitespace on both sides" - -- id: extra_whitespace_period - msg: "extraneous whitespace after '.' is not permitted" - -- id: lex_editor_placeholder - msg: "editor placeholder in source file" - -- id: lex_editor_placeholder_in_playground - msg: "editor placeholder in source file" - -- id: lex_conflict_marker_in_file - msg: "source control conflict marker in source file" - -- id: note_in_decl_extension - msg: "in %select{declaration|extension}0 of %1" - -- id: line_directive_style_deprecated - msg: "#line directive was renamed to #sourceLocation" - -- id: declaration_same_line_without_semi - msg: "consecutive declarations on a line must be separated by ';'" - -- id: expected_decl - msg: "expected declaration" - -- id: expected_identifier_in_decl - msg: "expected identifier in %0 declaration" - -- id: expected_keyword_in_decl - msg: "expected '%0' keyword in %1 declaration" - -- id: number_cant_start_decl_name - msg: "%0 name can only start with a letter or underscore, not a number" - -- id: expected_identifier_after_case_comma - msg: "expected identifier after comma in enum 'case' declaration" - -- id: decl_redefinition - msg: "definition conflicts with previous value" - -- id: let_cannot_be_computed_property - msg: "'let' declarations cannot be computed properties" - -- id: let_cannot_be_observing_property - msg: "'let' declarations cannot be observing properties" - -- id: let_cannot_be_addressed_property - msg: "'let' declarations cannot have addressors" - -- id: disallowed_var_multiple_getset - msg: "'var' declarations with multiple variables cannot have explicit getters/setters" - -- id: disallowed_init - msg: "initial value is not allowed here" - -- id: var_init_self_referential - msg: "variable used within its own initial value" - -- id: disallowed_enum_element - msg: "enum 'case' is not allowed outside of an enum" - -- id: decl_inner_scope - msg: "declaration is only valid at file scope" - -- id: decl_not_static - msg: "declaration cannot be marked %0" - -- id: cskeyword_not_attribute - msg: "'%0' is a declaration modifier, not an attribute" - -- id: decl_already_static - msg: "%0 cannot appear after another 'static' or 'class' keyword" - -- id: enum_case_dot_prefix - msg: "extraneous '.' in enum 'case' declaration" - -- id: static_var_decl_global_scope - msg: "%select{%error|static properties|class properties}0 may only be declared on a type" - -- id: computed_property_no_accessors - msg: "%select{computed property|subscript}0 must have accessors specified" - -- id: expected_getset_in_protocol - msg: "expected get or set in a protocol property" - -- id: computed_property_missing_type - msg: "computed property must have an explicit type" - -- id: getset_nontrivial_pattern - msg: "getter/setter can only be defined for a single variable" - -- id: expected_rbrace_in_getset - msg: "expected '}' at end of variable get/set clause" - -- id: duplicate_accessor - msg: "%select{variable|subscript}0 already has %1" - -- id: conflicting_accessor - msg: "%select{variable|subscript}0 cannot provide both %1 and %2" - -- id: previous_accessor - msg: "%select{|previous definition of }1%0 %select{defined |}1here" - -- id: expected_accessor_parameter_name - msg: "expected %select{setter|willSet|didSet}0 parameter name" - -- id: expected_rparen_set_name - msg: "expected ')' after setter parameter name" - -- id: expected_rparen_willSet_name - msg: "expected ')' after willSet parameter name" - -- id: expected_rparen_didSet_name - msg: "expected ')' after didSet parameter name" - -- id: expected_lbrace_accessor - msg: "expected '{' to start %0 definition" - -- id: expected_accessor_kw - msg: "expected 'get', 'set', 'willSet', or 'didSet' keyword to start an accessor definition" - -- id: missing_getter - msg: "%select{variable|subscript}0 with %1 must also have a getter" - -- id: missing_reading_accessor - msg: "%select{variable|subscript}0 with %1 must also have a getter, addressor, or 'read' accessor" - -- id: observing_accessor_conflicts_with_accessor - msg: "%select{'willSet'|'didSet'}0 cannot be provided together with %1" - -- id: observing_accessor_in_subscript - msg: "%select{'willSet'|'didSet'}0 is not allowed in subscripts" - -- id: getset_cannot_be_implied - msg: "variable with implied type cannot have implied getter/setter" - -- id: decl_expected_module_name - msg: "expected module name in import declaration" - -- id: expected_lbrace_extension - msg: "expected '{' in extension" - -- id: expected_rbrace_extension - msg: "expected '}' at end of extension" - -- id: extension_type_expected - msg: "expected type name in extension declaration" - -- id: expected_equal_in_typealias - msg: "expected '=' in type alias declaration" - -- id: expected_type_in_typealias - msg: "expected type in type alias declaration" - -- id: expected_type_in_associatedtype - msg: "expected type in associated type declaration" - -- id: associated_type_generic_parameter_list - msg: "associated types must not have a generic parameter list" - -- id: func_decl_without_paren - msg: "expected '(' in argument list of function declaration" - -- id: static_func_decl_global_scope - msg: "%select{%error|static methods|class methods}0 may only be declared on a type" - -- id: func_decl_expected_arrow - msg: "expected '->' after function parameter tuple" - -- id: operator_static_in_protocol - msg: "operator '%0' declared in protocol must be 'static'" - -- id: expected_lbrace_enum - msg: "expected '{' in enum" - -- id: expected_rbrace_enum - msg: "expected '}' at end of enum" - -- id: expected_lbrace_struct - msg: "expected '{' in struct" - -- id: expected_rbrace_struct - msg: "expected '}' in struct" - -- id: expected_lbrace_class - msg: "expected '{' in class" - -- id: expected_rbrace_class - msg: "expected '}' in class" - -- id: expected_colon_class - msg: "expected ':' to begin inheritance clause" - -- id: generic_arguments_protocol - msg: "protocols do not allow generic parameters; use associated types instead" - -- id: expected_lbrace_protocol - msg: "expected '{' in protocol type" - -- id: expected_rbrace_protocol - msg: "expected '}' in protocol" - -- id: protocol_setter_name - msg: "setter in a protocol cannot have a name" - -- id: protocol_method_with_body - msg: "protocol methods must not have bodies" - -- id: protocol_init_with_body - msg: "protocol initializers must not have bodies" - -- id: subscript_decl_wrong_scope - msg: "'subscript' functions may only be declared within a type" - -- id: expected_lparen_subscript - msg: "expected '(' for subscript parameters" - -- id: subscript_has_name - msg: "subscripts cannot have a name" - -- id: expected_arrow_subscript - msg: "expected '->' for subscript element type" - -- id: expected_type_subscript - msg: "expected subscripting element type" - -- id: expected_lbrace_subscript - msg: "expected '{' in subscript to specify getter and setter implementation" - -- id: expected_lbrace_subscript_protocol - msg: "subscript in protocol must have explicit { get } or { get set } specifier" - -- id: subscript_without_get - msg: "subscript declarations must have a getter" - -- id: invalid_nested_init - msg: "missing '%select{super.|self.}0' at initializer invocation" - -- id: initializer_decl_wrong_scope - msg: "initializers may only be declared within a type" - -- id: expected_lparen_initializer - msg: "expected '(' for initializer parameters" - -- id: initializer_has_name - msg: "initializers cannot have a name" - -- id: destructor_decl_outside_class - msg: "deinitializers may only be declared within a class" - -- id: expected_lbrace_destructor - msg: "expected '{' for deinitializer" - -- id: destructor_has_name - msg: "deinitializers cannot have a name" - -- id: opened_destructor_expected_rparen - msg: "expected ')' to close parameter list" - -- id: destructor_params - msg: "no parameter clause allowed on deinitializer" - -- id: operator_decl_inner_scope - msg: "'operator' may only be declared at file scope" - -- id: expected_operator_name_after_operator - msg: "expected operator name in operator declaration" - -- id: identifier_within_operator_name - msg: "'%0' is considered an identifier and must not appear within an operator name" - -- id: operator_name_invalid_char - msg: "'%0' is not allowed in operator names" - -- id: postfix_operator_name_cannot_start_with_unwrap - msg: "postfix operator names starting with '?' or '!' are disallowed to avoid collisions with built-in unwrapping operators" - -- id: deprecated_operator_body - msg: "operator should no longer be declared with body" - -- id: deprecated_operator_body_use_group - msg: "operator should no longer be declared with body; use a precedence group instead" - -- id: operator_decl_no_fixity - msg: "operator must be declared as 'prefix', 'postfix', or 'infix'" - -- id: operator_decl_expected_type - msg: "expected designated type in operator declaration" - -- id: operator_decl_trailing_comma - msg: "trailing comma in operator declaration" - -- id: precedencegroup_not_infix - msg: "only infix operators may declare a precedence" - -- id: expected_precedencegroup_name - msg: "expected identifier after 'precedencegroup'" - -- id: expected_precedencegroup_lbrace - msg: "expected '{' after name of precedence group" - -- id: expected_precedencegroup_attribute - msg: "expected operator attribute identifier in precedence group body" - -- id: unknown_precedencegroup_attribute - msg: "'%0' is not a valid precedence group attribute" - -- id: expected_precedencegroup_attribute_colon - msg: "expected colon after attribute name in precedence group" - -- id: precedencegroup_attribute_redeclared - msg: "'%0' attribute for precedence group declared multiple times" - -- id: expected_precedencegroup_associativity - msg: "expected 'none', 'left', or 'right' after 'associativity'" - -- id: expected_precedencegroup_assignment - msg: "expected 'true' or 'false' after 'assignment'" - -- id: expected_precedencegroup_relation - msg: "expected name of related precedence group after '%0'" - -- id: expected_sil_keyword - msg: "expected SIL keyword" - -- id: inout_not_attribute - msg: "@inout is no longer an attribute" - -- id: only_allowed_in_sil - msg: "'%0' only allowed in SIL modules" - -- id: expected_sil_type - msg: "expected type in SIL code" - -- id: expected_sil_colon_value_ref - msg: "expected ':' before type in SIL value reference" - -- id: expected_sil_value_name - msg: "expected SIL value name" - -- id: expected_sil_type_kind - msg: "expected SIL type to %0" - -- id: expected_sil_constant - msg: "expected constant in SIL code" - -- id: referenced_value_no_accessor - msg: "referenced declaration has no %select{getter|setter}0" - -- id: expected_sil_value_ownership_kind - msg: "expected value ownership kind in SIL code" - -- id: silfunc_and_silarg_have_incompatible_sil_value_ownership - msg: "SILFunction and SILArgument have mismatching ValueOwnershipKinds. Function type specifies: '@%0'. SIL argument specifies: '@%1'." - -- id: expected_sil_colon - msg: "expected ':' before %0" - -- id: expected_sil_tuple_index - msg: "expected tuple element index" - -- id: invalid_index_subset - msg: "invalid index subset; expected '[SU]+' where 'S' represents set indices and 'U' represents unset indices" - -- id: sil_value_redefinition - msg: "redefinition of value '%0'" - -- id: sil_value_use_type_mismatch - msg: "value '%0' defined with mismatching type %1 (expected %2)" - -- id: sil_value_def_type_mismatch - msg: "value '%0' used with mismatching type %1 (expected %2)" - -- id: sil_use_of_undefined_value - msg: "use of undefined value '%0'" - -- id: sil_prior_reference - msg: "prior reference was here" - -- id: expected_colon_in_sil_location - msg: "expected ':' in SIL location" - -- id: sil_invalid_line_in_sil_location - msg: "line number must be a positive integer" - -- id: sil_invalid_column_in_sil_location - msg: "column number must be a positive integer" - -- id: sil_invalid_scope_slot - msg: "scope number must be a positive integer " - -- id: sil_scope_undeclared - msg: "scope number %0 needs to be declared before first use" - -- id: sil_scope_redefined - msg: "scope number %0 is already defined" - -- id: expected_sil_instr_start_of_line - msg: "SIL instructions must be at the start of a line" - -- id: expected_equal_in_sil_instr - msg: "expected '=' in SIL instruction" - -- id: wrong_result_count_in_sil_instr - msg: "wrong number of results for SIL instruction, expected %0" - -- id: expected_sil_instr_opcode - msg: "expected SIL instruction opcode" - -- id: expected_tok_in_sil_instr - msg: "expected '%0' in SIL instruction" - -- id: sil_property_generic_signature_mismatch - msg: "sil_property generic signature must match original declaration" - -- id: sil_string_no_encoding - msg: "string_literal instruction requires an encoding" - -- id: sil_string_invalid_encoding - msg: "unknown string literal encoding '%0'" - -- id: expected_tuple_type_in_tuple - msg: "tuple instruction requires a tuple type" - -- id: sil_tuple_inst_wrong_value_count - msg: "tuple instruction requires %0 values" - -- id: sil_tuple_inst_wrong_field - msg: "tuple instruction requires a field number" - -- id: sil_struct_inst_wrong_field - msg: "struct instruction requires a field name" - -- id: sil_ref_inst_wrong_field - msg: "ref_element_addr instruction requires a field name" - -- id: sil_invalid_instr_operands - msg: "invalid instruction operands" - -- id: sil_operand_not_address - msg: "%0 operand of '%1' must have address type" - -- id: sil_operand_not_ref_storage_address - msg: "%0 operand of '%1' must have address of %2 type" - -- id: sil_integer_literal_not_integer_type - msg: "integer_literal instruction requires a 'Builtin.Int' type" - -- id: sil_integer_literal_not_well_formed - msg: "integer_literal value not well-formed for type %0" - -- id: sil_float_literal_not_float_type - msg: "float_literal instruction requires a 'Builtin.FP' type" - -- id: sil_substitutions_on_non_polymorphic_type - msg: "apply of non-polymorphic function cannot have substitutions" - -- id: sil_witness_method_not_protocol - msg: "witness_method is not a protocol method" - -- id: sil_witness_method_type_does_not_conform - msg: "witness_method type does not conform to protocol" - -- id: sil_member_decl_not_found - msg: "member not found" - -- id: sil_named_member_decl_not_found - msg: "member %0 not found in type %1" - -- id: sil_member_lookup_bad_type - msg: "cannot lookup member %0 in non-nominal, non-module type %1" - -- id: sil_member_decl_type_mismatch - msg: "member defined with mismatching type %0 (expected %1)" - -- id: sil_substitution_mismatch - msg: "substitution replacement type %0 does not conform to protocol %1" - -- id: sil_not_class - msg: "substitution replacement type %0 is not a class type" - -- id: sil_missing_substitutions - msg: "missing substitutions" - -- id: sil_too_many_substitutions - msg: "too many substitutions" - -- id: sil_dbg_unknown_key - msg: "unknown key '%0' in debug variable declaration" - -- id: sil_objc_with_tail_elements - msg: "alloc_ref [objc] cannot have tail allocated elements" - -- id: sil_expected_access_kind - msg: "%0 instruction must have explicit access kind" - -- id: sil_expected_access_enforcement - msg: "%0 instruction must have explicit access enforcement" - -- id: sil_keypath_expected_component_kind - msg: "expected keypath component kind" - -- id: sil_keypath_unknown_component_kind - msg: "unknown keypath component kind %0" - -- id: sil_keypath_computed_property_missing_part - msg: "keypath %select{gettable|settable}0_property component needs an %select{id and getter|id, getter, and setter}0" - -- id: sil_keypath_no_root - msg: "keypath must have a root component declared" - -- id: sil_keypath_index_not_hashable - msg: "key path index type %0 does not conform to Hashable" - -- id: sil_keypath_index_operand_type_conflict - msg: "conflicting types for key path operand %0: %1 vs. %2" - -- id: sil_keypath_no_use_of_operand_in_pattern - msg: "operand %0 is not referenced by any component in the pattern" - -- id: expected_sil_block_name - msg: "expected basic block name or '}'" - -- id: expected_sil_block_colon - msg: "expected ':' after basic block name" - -- id: sil_undefined_basicblock_use - msg: "use of undefined basic block %0" - -- id: sil_basicblock_redefinition - msg: "redefinition of basic block %0" - -- id: sil_basicblock_arg_rparen - msg: "expected ')' in basic block argument list" - -- id: expected_sil_function_name - msg: "expected SIL function name" - -- id: expected_sil_rbrace - msg: "expected '}' at the end of a sil body" - -- id: expected_sil_function_type - msg: "sil function expected to have SIL function type" - -- id: sil_dynamically_replaced_func_not_found - msg: "dynamically replaced function not found %0" - -- id: sil_availability_expected_version - msg: "expected version number in 'available' attribute" - -- id: expected_sil_stage_name - msg: "expected 'raw' or 'canonical' after 'sil_stage'" - -- id: multiple_sil_stage_decls - msg: "sil_stage declared multiple times" - -- id: expected_sil_vtable_colon - msg: "expected ':' in a vtable entry" - -- id: sil_vtable_func_not_found - msg: "sil function not found %0" - -- id: sil_vtable_class_not_found - msg: "sil class not found %0" - -- id: sil_vtable_bad_entry_kind - msg: "expected 'inherited' or 'override'" - -- id: sil_vtable_expect_rsquare - msg: "expected ']' after vtable entry kind" - -- id: sil_global_variable_not_found - msg: "sil global not found %0" - -- id: expected_sil_witness_colon - msg: "expected ':' in a witness table" - -- id: expected_sil_witness_lparen - msg: "expected '(' in a witness table" - -- id: expected_sil_witness_rparen - msg: "expected ')' in a witness table" - -- id: sil_witness_func_not_found - msg: "sil function not found %0" - -- id: sil_witness_protocol_not_found - msg: "sil protocol not found %0" - -- id: sil_witness_assoc_not_found - msg: "sil associated type decl not found %0" - -- id: sil_witness_assoc_conf_not_found - msg: "sil associated type path for conformance not found %0" - -- id: sil_witness_protocol_conformance_not_found - msg: "sil protocol conformance not found" - -- id: sil_diff_witness_expected_token - msg: "expected '%0' in differentiability witness" - -- id: sil_diff_witness_serialized_declaration - msg: "differentiability witness declaration should not be serialized" - -- id: sil_diff_witness_undefined - msg: "reference to undefined differentiability witness" - -- id: sil_diff_witness_invalid_generic_signature - msg: "expected witness generic signature '%0' does not have same generic parameters as original function generic signature '%1'" - -- id: sil_coverage_invalid_hash - msg: "expected coverage hash" - -- id: sil_coverage_expected_lbrace - msg: "expected '{' in coverage map" - -- id: sil_coverage_expected_loc - msg: "expected line:column pair" - -- id: sil_coverage_expected_arrow - msg: "expected '->' after start location" - -- id: sil_coverage_expected_colon - msg: "expected ':' after source range" - -- id: sil_coverage_invalid_counter - msg: "expected counter expression, id, or 'zero'" - -- id: sil_coverage_expected_rparen - msg: "expected ')' to end counter expression" - -- id: sil_coverage_expected_quote - msg: "expected quotes surrounding PGO function name" - -- id: sil_coverage_invalid_operator - msg: "expected '+' or '-'" - -- id: expected_type - msg: "expected type" - -- id: expected_init_value - msg: "expected initial value after '='" - -- id: expected_identifier_in_dotted_type - msg: "expected identifier in dotted type" - -- id: expected_identifier_for_type - msg: "expected identifier for type name" - -- id: expected_rangle_generic_arg_list - msg: "expected '>' to complete generic argument list" - -- id: expected_type_function_result - msg: "expected type for function result" - -- id: generic_non_function - msg: "only syntactic function types can be generic" - -- id: rethrowing_function_type - msg: "only function declarations may be marked 'rethrows'; did you mean 'throws'?" - -- id: async_or_throws_in_wrong_position - msg: "%select{'throws'|'rethrows'|'async'}0 may only occur before '->'" - -- id: throw_in_function_type - msg: "expected throwing specifier; did you mean 'throws'?" - -- id: expected_type_before_arrow - msg: "expected type before '->'" - -- id: expected_type_after_arrow - msg: "expected type after '->'" - -- id: function_type_argument_label - msg: "function types cannot have argument labels; use '_' before %0" - -- id: expected_dynamic_func_attr - msg: "expected a dynamically_replaceable function" - -- id: async_after_throws - msg: "'async' must precede %select{'throws'|'rethrows'}0" - -- id: async_init - msg: "initializer cannot be marked 'async'" - -- id: expected_expr_enum_case_raw_value - msg: "expected expression after '=' in 'case'" - -- id: nonliteral_enum_case_raw_value - msg: "raw value for enum case must be a literal" - -- id: new_array_syntax - msg: "array types are now written with the brackets around the element type" - -- id: expected_rbracket_array_type - msg: "expected ']' in array type" - -- id: expected_element_type - msg: "expected element type" - -- id: expected_dictionary_value_type - msg: "expected dictionary value type" - -- id: expected_rbracket_dictionary_type - msg: "expected ']' in dictionary type" - -- id: extra_rbracket - msg: "unexpected ']' in type; did you mean to write an array type?" - -- id: extra_colon - msg: "unexpected ':' in type; did you mean to write a dictionary type?" - -- id: subscript_array_element - msg: "unexpected subscript in array literal; did you mean to write two separate elements instead?" - -- id: subscript_array_element_fix_it_add_comma - msg: "add a separator between the elements" - -- id: subscript_array_element_fix_it_remove_space - msg: "remove the space between the elements to silence this warning" - -- id: expected_rparen_tuple_type_list - msg: "expected ')' at end of tuple list" - -- id: multiple_ellipsis_in_tuple - msg: "only a single element can be variadic" - -- id: tuple_type_init - msg: "default argument not permitted in a tuple type" - -- id: protocol_method_argument_init - msg: "default argument not permitted in a protocol method" - -- id: protocol_init_argument_init - msg: "default argument not permitted in a protocol initializer" - -- id: tuple_type_multiple_labels - msg: "tuple element cannot have two labels" - -- id: expected_rangle_protocol - msg: "expected '>' to complete protocol-constrained type" - -- id: deprecated_protocol_composition - msg: "'protocol<...>' composition syntax has been removed; join the protocols using '&'" - -- id: deprecated_protocol_composition_single - msg: "'protocol<...>' composition syntax has been removed and is not needed here" - -- id: deprecated_any_composition - msg: "'protocol<>' syntax has been removed; use 'Any' instead" - -- id: sil_box_expected_var_or_let - msg: "expected 'var' or 'let' to introduce SIL box field type" - -- id: sil_box_expected_r_brace - msg: "expected '}' to complete SIL box field type list" - -- id: sil_box_expected_r_angle - msg: "expected '>' to complete SIL box generic argument list" - -- id: sil_function_subst_expected_l_angle - msg: "expected '<' to begin SIL function type substitution list after 'for'" - -- id: sil_function_subst_expected_r_angle - msg: "expected '>' to end SIL function type substitution list after 'for <...'" - -- id: sil_function_subst_expected_generics - msg: "expected '<' to begin substituted parameter list after '@substituted'" - -- id: sil_function_subst_expected_function - msg: "expected function type after '@substituted'" - -- id: sil_function_subst_expected_subs - msg: "expected 'for' to begin substitutions after '@substituted' function type" - -- id: sil_function_subs_without_generics - msg: "unexpected 'for' to begin substitutions after non-generic function type" - -- id: opaque_mid_composition - msg: "'some' should appear at the beginning of a composition" - -- id: layout_size_should_be_positive - msg: "expected non-negative size to be specified in layout constraint" - -- id: layout_alignment_should_be_positive - msg: "expected non-negative alignment to be specified in layout constraint" - -- id: expected_rparen_layout_constraint - msg: "expected ')' to complete layout constraint" - -- id: layout_constraints_only_inside_specialize_attr - msg: "layout constraints are only allowed inside '_specialize' attributes" - -- id: expected_pattern - msg: "expected pattern" - -- id: keyword_cant_be_identifier - msg: "keyword '%0' cannot be used as an identifier here" - -- id: repeated_identifier - msg: "found an unexpected second identifier in %0 declaration; is there an accidental break?" - -- id: join_identifiers - msg: "join the identifiers together" - -- id: join_identifiers_camel_case - msg: "join the identifiers together with camel-case" - -- id: backticks_to_escape - msg: "if this name is unavoidable, use backticks to escape it" - -- id: expected_rparen_tuple_pattern_list - msg: "expected ')' at end of tuple pattern" - -- id: untyped_pattern_ellipsis - msg: "'...' cannot be applied to a subpattern which is not explicitly typed" - -- id: no_default_arg_closure - msg: "default arguments are not allowed in closures" - -- id: no_default_arg_curried - msg: "default arguments are not allowed in curried parameter lists" - -- id: var_pattern_in_var - msg: "'%select{var|let}0' cannot appear nested inside another 'var' or 'let' pattern" - -- id: extra_var_in_multiple_pattern_list - msg: "%0 must be bound in every pattern" - -- id: let_pattern_in_immutable_context - msg: "'let' pattern cannot appear nested in an already immutable context" - -- id: specifier_must_have_type - msg: "%0 arguments must have a type specified" - -- id: expected_rparen_parameter - msg: "expected ')' in parameter" - -- id: expected_parameter_type - msg: "expected parameter type following ':'" - -- id: expected_parameter_name - msg: "expected parameter name followed by ':'" - -- id: expected_parameter_colon - msg: "expected ':' following argument label and parameter name" - -- id: expected_assignment_instead_of_comparison_operator - msg: "expected '=' instead of '==' to assign default value for parameter" - -- id: multiple_parameter_ellipsis - msg: "only a single variadic parameter '...' is permitted" - -- id: parameter_vararg_default - msg: "variadic parameter cannot have a default value" - -- id: parameter_specifier_as_attr_disallowed - msg: "'%0' before a parameter name is not allowed, place it before the parameter type instead" - -- id: parameter_specifier_repeated - msg: "parameter must not have multiple '__owned', 'inout', or '__shared' specifiers" - -- id: parameter_let_var_as_attr - msg: "'%0' in this position is interpreted as an argument label" - -- id: parameter_extraneous_double_up - msg: "extraneous duplicate parameter name; %0 already has an argument label" - -- id: parameter_operator_keyword_argument - msg: "%select{operator|closure|enum case}0 cannot have keyword arguments" - -- id: parameter_unnamed - msg: "unnamed parameters must be written with the empty name '_'" - -- id: parameter_unnamed_warn - msg: "unnamed parameters must be written with the empty name '_'" - -- id: parameter_curry_syntax_removed - msg: "cannot have more than one parameter list" - -- id: initializer_as_typed_pattern - msg: "unexpected initializer in pattern; did you mean to use '='?" - -- id: unlabeled_parameter_following_variadic_parameter - msg: "a parameter following a variadic parameter requires a label" - -- id: enum_element_empty_arglist - msg: "enum element with associated values must have at least one associated value" - -- id: enum_element_empty_arglist_swift4 - msg: "enum element with associated values must have at least one associated value; this will be an error in the future version of Swift" - -- id: enum_element_empty_arglist_delete - msg: "did you mean to remove the empty associated value list?" - -- id: enum_element_empty_arglist_add_void - msg: "did you mean to explicitly add a 'Void' associated value?" - -- id: expected_stmt - msg: "expected statement" - -- id: illegal_top_level_stmt - msg: "statements are not allowed at the top level" - -- id: illegal_top_level_expr - msg: "expressions are not allowed at the top level" - -- id: illegal_semi_stmt - msg: "';' statements are not allowed" - -- id: statement_begins_with_closure - msg: "top-level statement cannot begin with a closure expression" - -- id: statement_same_line_without_semi - msg: "consecutive statements on a line must be separated by ';'" - -- id: invalid_label_on_stmt - msg: "labels are only valid on loops, if, and switch statements" - -- id: labeled_block_needs_do - msg: "labeled block needs 'do'" - -- id: snake_case_deprecated - msg: "%0 has been replaced with %1 in Swift 3" - -- id: expected_expr_assignment - msg: "expected expression in assignment" - -- id: expected_rbrace_in_brace_stmt - msg: "expected '}' at end of brace statement" - -- id: typealias_inside_protocol_without_type - msg: "type alias is missing an assigned type; use 'associatedtype' to define an associated type requirement" - -- id: associatedtype_outside_protocol - msg: "associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement" - -- id: expected_expr_return - msg: "expected expression in 'return' statement" - -- id: unindented_code_after_return - msg: "expression following 'return' is treated as an argument of the 'return'" - -- id: indent_expression_to_silence - msg: "indent the expression to silence this warning" - -- id: expected_expr_throw - msg: "expected expression in 'throw' statement" - -- id: expected_expr_yield - msg: "expected expression in 'yield' statement" - -- id: expected_lbrace_after_defer - msg: "expected '{' after 'defer'" - -- id: expected_comma_stmtcondition - msg: "expected ',' joining parts of a multi-clause condition" - -- id: expected_expr_conditional - msg: "expected expression in conditional" - -- id: expected_binding_keyword - msg: "expected '%0' in conditional" - -- id: expected_expr_conditional_var - msg: "expected expression after '=' in conditional binding" - -- id: conditional_var_initializer_required - msg: "variable binding in a condition requires an initializer" - -- id: wrong_condition_case_location - msg: "pattern matching binding is spelled with 'case %0', not '%0 case'" - -- id: expected_condition_if - msg: "expected expression, var, or let in 'if' condition" - -- id: missing_condition_after_if - msg: "missing condition in an 'if' statement" - -- id: expected_lbrace_after_if - msg: "expected '{' after 'if' condition" - -- id: expected_lbrace_or_if_after_else - msg: "expected '{' or 'if' after 'else'" - -- id: expected_lbrace_or_if_after_else_fixit - msg: "expected '{' or 'if' after 'else'; did you mean to write 'if'?" - -- id: unexpected_else_after_if - msg: "unexpected 'else' immediately following 'if' condition" - -- id: suggest_removing_else - msg: "remove 'else' to execute the braced block of statements when the condition is true" - -- id: expected_condition_guard - msg: "expected expression, var, let or case in 'guard' condition" - -- id: missing_condition_after_guard - msg: "missing condition in an 'guard' statement" - -- id: expected_else_after_guard - msg: "expected 'else' after 'guard' condition" - -- id: expected_lbrace_after_guard - msg: "expected '{' after 'guard' else" - -- id: bound_var_guard_body - msg: "variable declared in 'guard' condition is not usable in its body" - -- id: expected_condition_while - msg: "expected expression, var, or let in 'while' condition" - -- id: missing_condition_after_while - msg: "missing condition in a 'while' statement" - -- id: expected_lbrace_after_while - msg: "expected '{' after 'while' condition" - -- id: expected_lbrace_after_repeat - msg: "expected '{' after 'repeat'" - -- id: expected_while_after_repeat_body - msg: "expected 'while' after body of 'repeat' statement" - -- id: expected_expr_repeat_while - msg: "expected expression in 'repeat-while' condition" - -- id: do_while_now_repeat_while - msg: "'do-while' statement is not allowed" - -- id: do_while_expected_repeat_while - msg: "did you mean 'repeat-while' statement?" - -- id: do_while_expected_separate_stmt - msg: "did you mean separate 'do' and 'while' statements?" - -- id: expected_lbrace_after_do - msg: "expected '{' after 'do'" - -- id: expected_lbrace_after_catch - msg: "expected '{' after 'catch' pattern" - -- id: expected_catch_where_expr - msg: "expected expression for 'where' guard of 'catch'" - -- id: docatch_not_trycatch - msg: "the 'do' keyword is used to specify a 'catch' region" - -- id: c_style_for_stmt_removed - msg: "C-style for statement has been removed in Swift 3" - -- id: expected_foreach_in - msg: "expected 'in' after for-each pattern" - -- id: expected_foreach_container - msg: "expected Sequence expression for for-each loop" - -- id: expected_foreach_lbrace - msg: "expected '{' to start the body of for-each loop" - -- id: expected_foreach_where_expr - msg: "expected expression in 'where' guard of 'for/in'" - -- id: expected_switch_expr - msg: "expected expression in 'switch' statement" - -- id: expected_lbrace_after_switch - msg: "expected '{' after 'switch' subject expression" - -- id: expected_rbrace_switch - msg: "expected '}' at end of 'switch' statement" - -- id: case_outside_of_switch - msg: "'%0' label can only appear inside a 'switch' statement" - -- id: stmt_in_switch_not_covered_by_case - msg: "all statements inside a switch must be covered by a 'case' or 'default'" - -- id: case_after_default - msg: "additional 'case' blocks cannot appear after the 'default' block of a 'switch'" - -- id: expected_case_where_expr - msg: "expected expression for 'where' guard of 'case'" - -- id: expected_case_colon - msg: "expected ':' after '%0'" - -- id: default_with_where - msg: "'default' cannot be used with a 'where' guard expression" - -- id: case_stmt_without_body - msg: "%select{'case'|'default'}0 label in a 'switch' should have at least one executable statement" - -- id: try_on_stmt - msg: "'try' cannot be used with '%0'" - -- id: try_on_return_throw_yield - msg: "'try' must be placed on the %select{returned|thrown|yielded}0 expression" - -- id: try_on_var_let - msg: "'try' must be placed on the initial value expression" - -- id: expected_expr - msg: "expected expression" - -- id: expected_separator - msg: "expected '%0' separator" - -- id: unexpected_separator - msg: "unexpected '%0' separator" - -- id: expected_expr_after_operator - msg: "expected expression after operator" - -- id: expected_expr_after_unary_operator - msg: "expected expression after unary operator" - -- id: expected_prefix_operator - msg: "unary operator cannot be separated from its operand" - -- id: expected_operator_ref - msg: "expected operator name in operator reference" - -- id: invalid_postfix_operator - msg: "operator with postfix spacing cannot start a subexpression" - -- id: expected_member_name - msg: "expected member name following '.'" - -- id: dollar_numeric_too_large - msg: "numeric value following '$' is too large" - -- id: numeric_literal_numeric_member - msg: "expected named member of numeric literal" - -- id: standalone_dollar_identifier - msg: "'$' is not an identifier; use backticks to escape it" - -- id: dollar_identifier_decl - msg: "cannot declare entity named %0; the '$' prefix is reserved for implicitly-synthesized declarations" - -- id: anon_closure_arg_not_in_closure - msg: "anonymous closure argument not contained in a closure" - -- id: anon_closure_arg_in_closure_with_args - msg: "anonymous closure arguments cannot be used inside a closure that has explicit arguments" - -- id: anon_closure_arg_in_closure_with_args_typo - msg: "anonymous closure arguments cannot be used inside a closure that has explicit arguments; did you mean '%0'?" - -- id: anon_closure_tuple_param_destructuring - msg: "closure tuple parameter does not support destructuring" - -- id: expected_closure_parameter_name - msg: "expected the name of a closure parameter" - -- id: expected_capture_specifier - msg: "expected 'weak', 'unowned', or no specifier in capture list" - -- id: expected_capture_specifier_name - msg: "expected name of in closure capture list" - -- id: expected_init_capture_specifier - msg: "expected initializer for closure capture specifier" - -- id: expected_capture_list_end_rsquare - msg: "expected ']' at end of capture list" - -- id: cannot_capture_fields - msg: "fields may only be captured by assigning to a specific name" - -- id: expected_closure_result_type - msg: "expected closure result type after '->'" - -- id: expected_closure_in - msg: "expected 'in' after the closure signature" - -- id: unexpected_tokens_before_closure_in - msg: "unexpected tokens prior to 'in'" - -- id: expected_closure_rbrace - msg: "expected '}' at end of closure" - -- id: trailing_closure_after_newlines - msg: "braces here form a trailing closure separated from its callee by multiple newlines" - -- id: trailing_closure_callee_here - msg: "callee is here" - -- id: string_literal_no_atsign - msg: "string literals in Swift are not preceded by an '@' sign" - -- id: invalid_float_literal_missing_leading_zero - msg: "'.%0' is not a valid floating point literal; it must be written '0.%0'" - -- id: availability_query_outside_if_stmt_guard - msg: "#available may only be used as condition of an 'if', 'guard' or 'while' statement" - -- id: empty_arg_label_underscore - msg: "an empty argument label is spelled with '_'" - -- id: expected_identifier_after_dot_expr - msg: "expected identifier after '.' expression" - -- id: expected_identifier_after_super_dot_expr - msg: "expected identifier or 'init' after super '.' expression" - -- id: expected_dot_or_subscript_after_super - msg: "expected '.' or '[' after 'super'" - -- id: super_in_closure_with_capture - msg: "using 'super' in a closure where 'self' is explicitly captured is not yet supported" - -- id: super_in_closure_with_capture_here - msg: "'self' explicitly captured here" - -- id: expected_expr_in_expr_list - msg: "expected expression in list of expressions" - -- id: expected_expr_in_collection_literal - msg: "expected expression in container literal" - -- id: expected_key_in_dictionary_literal - msg: "expected key expression in dictionary literal" - -- id: expected_value_in_dictionary_literal - msg: "expected value in dictionary literal" - -- id: expected_colon_in_dictionary_literal - msg: "expected ':' in dictionary literal" - -- id: expected_rparen_expr_list - msg: "expected ')' in expression list" - -- id: expected_rsquare_expr_list - msg: "expected ']' in expression list" - -- id: expected_rsquare_array_expr - msg: "expected ']' in container literal expression" - -- id: expected_arg_list_in_object_literal - msg: "expected argument list in object literal" - -- id: legacy_object_literal - msg: "'%select{|[}0#%1(...)%select{|#]}0' has been renamed to '#%2(...)'" - -- id: unknown_pound_expr - msg: "use of unknown directive '#%0'" - -- id: expected_expr_after_if_question - msg: "expected expression after '?' in ternary expression" - -- id: expected_colon_after_if_question - msg: "expected ':' after '? ...' in ternary expression" - -- id: expected_expr_after_if_colon - msg: "expected expression after '? ... :' in ternary expression" - -- id: expected_expr_after_try - msg: "expected expression after 'try'" - -- id: expected_expr_after_await - msg: "expected expression after 'await'" - -- id: expected_type_after_is - msg: "expected type after 'is'" - -- id: expected_type_after_as - msg: "expected type after 'as'" - -- id: string_interpolation_extra - msg: "extra tokens after interpolated string expression" - -- id: string_interpolation_list_changing - msg: "interpolating multiple values will not form a tuple in Swift 5" - -- id: string_interpolation_list_insert_parens - msg: "insert parentheses to keep current behavior" - -- id: string_interpolation_label_changing - msg: "labeled interpolations will not be ignored in Swift 5" - -- id: string_interpolation_remove_label - msg: "remove %0 label to keep current behavior" - -- id: expr_keypath_expected_lparen - msg: "expected '(' following '#keyPath'" - -- id: expr_keypath_expected_property_or_type - msg: "expected property or type name within '#keyPath(...)'" - -- id: expr_keypath_expected_rparen - msg: "expected ')' to complete '#keyPath' expression" - -- id: expr_keypath_expected_expr - msg: "expected expression path in Swift key path" - -- id: expr_selector_expected_lparen - msg: "expected '(' following '#selector'" - -- id: expr_selector_expected_method_expr - msg: "expected expression naming a method within '#selector(...)'" - -- id: expr_selector_expected_property_expr - msg: "expected expression naming a property within '#selector(...)'" - -- id: expr_selector_expected_rparen - msg: "expected ')' to complete '#selector' expression" - -- id: expr_dynamictype_deprecated - msg: "'.dynamicType' is deprecated. Use 'type(of: ...)' instead" - -- id: pound_assert_disabled - msg: "#assert is an experimental feature that is currently disabled" - -- id: pound_assert_expected_lparen - msg: "expected '(' in #assert directive" - -- id: pound_assert_expected_rparen - msg: "expected ')' in #assert directive" - -- id: pound_assert_expected_expression - msg: "expected a condition expression" - -- id: pound_assert_expected_string_literal - msg: "expected a string literal" - -- id: replace_equal_with_colon_for_value - msg: "'=' has been replaced with ':' in attribute arguments" - -- id: expected_attribute_name - msg: "expected an attribute name" - -- id: unknown_attribute - msg: "unknown attribute '%0'" - -- id: unexpected_lparen_in_attribute - msg: "unexpected '(' in attribute '%0'" - -- id: duplicate_attribute - msg: "duplicate %select{attribute|modifier}0" - -- id: previous_attribute - msg: "%select{attribute|modifier}0 already specified here" - -- id: mutually_exclusive_attrs - msg: "'%0' contradicts previous %select{attribute|modifier}2 '%1'" - -- id: invalid_infix_on_func - msg: "'infix' modifier is not required or allowed on func declarations" - -- id: expected_in_attribute_list - msg: "expected ']' or ',' in attribute list" - -- id: type_attribute_applied_to_decl - msg: "attribute can only be applied to types, not declarations" - -- id: decl_attribute_applied_to_type - msg: "attribute can only be applied to declarations, not types" - -- id: attr_expected_lparen - msg: "expected '(' in '%0' %select{attribute|modifier}1" - -- id: attr_expected_rparen - msg: "expected ')' in '%0' %select{attribute|modifier}1" - -- id: attr_expected_comma - msg: "expected ',' in '%0' %select{attribute|modifier}1" - -- id: attr_expected_string_literal - msg: "expected string literal in '%0' attribute" - -- id: attr_missing_label - msg: "missing label '%0:' in '@%1' attribute" - -- id: attr_expected_label - msg: "expected label '%0:' in '@%1' attribute" - -- id: alignment_must_be_positive_integer - msg: "alignment value must be a positive integer literal" - -- id: swift_native_objc_runtime_base_must_be_identifier - msg: "@_swift_native_objc_runtime_base class name must be an identifier" - -- id: objc_runtime_name_must_be_identifier - msg: "@_objcRuntimeName name must be an identifier" - -- id: attr_only_at_non_local_scope - msg: "attribute '%0' can only be used in a non-local scope" - -- id: projection_value_property_not_identifier - msg: "@_projectedValueProperty name must be an identifier" - -- id: attr_access_expected_set - msg: "expected 'set' as subject of '%0' modifier" - -- id: attr_access_expected_spi_name - msg: "expected an SPI identifier as subject of the '@_spi' attribute" - -- id: attr_renamed - msg: "'@%0' has been renamed to '@%1'" - -- id: attr_renamed_warning - msg: "'@%0' has been renamed to '@%1'" - -- id: attr_name_close_match - msg: "no attribute named '@%0'; did you mean '@%1'?" - -- id: attr_unsupported_on_target - msg: "attribute '%0' is unsupported on target '%1'" - -- id: attr_availability_platform - msg: "expected platform name or '*' for '%0' attribute" - -- id: attr_availability_unavailable_deprecated - msg: "'%0' attribute cannot be both unconditionally 'unavailable' and 'deprecated'" - -- id: attr_availability_invalid_duplicate - msg: "'%0' argument has already been specified" - -- id: attr_availability_unknown_platform - msg: "unknown platform '%0' for attribute '%1'" - -- id: attr_availability_invalid_renamed - msg: "'renamed' argument of '%0' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name" - -- id: attr_availability_expected_option - msg: "expected '%0' option such as 'unavailable', 'introduced', 'deprecated', 'obsoleted', 'message', or 'renamed'" - -- id: attr_availability_expected_equal - msg: "expected ':' after '%1' in '%0' attribute" - -- id: attr_availability_expected_version - msg: "expected version number in '%0' attribute" - -- id: attr_availability_platform_agnostic_expected_option - msg: "expected 'introduced', 'deprecated', or 'obsoleted' in '%0' attribute for platform '%1'" - -- id: attr_availability_platform_agnostic_expected_deprecated_version - msg: "expected version number with 'deprecated' in '%0' attribute for platform '%1'" - -- id: attr_availability_platform_agnostic_infeasible_option - msg: "'%0' cannot be used in '%1' attribute for platform '%2'" - -- id: attr_availability_nonspecific_platform_unexpected_version - msg: "unexpected version number in '%0' attribute for non-specific platform '*'" - -- id: originally_defined_in_missing_rparen - msg: "expected ')' in @_originallyDefinedIn argument list" - -- id: originally_defined_in_unrecognized_platform - msg: "unrecognized platform name in @_originallyDefinedIn argument list" - -- id: originally_defined_in_unrecognized_property - msg: "unrecognized property in @_originallyDefinedIn argument list" - -- id: originally_defined_in_need_original_module_name - msg: "expected 'module: \"original\"' in the first argument to @_originallyDefinedIn" - -- id: originally_defined_in_need_nonempty_module_name - msg: "original module name cannot be empty in @_originallyDefinedIn" - -- id: originally_defined_in_need_platform_version - msg: "expected at least one platform version in @_originallyDefinedIn" - -- id: originally_defined_in_major_minor_only - msg: "@_originallyDefinedIn only uses major and minor version number" - -- id: originally_defined_in_missing_platform_name - msg: "* as platform name has no effect" - -- id: convention_attribute_expected_lparen - msg: "expected '(' after 'convention' attribute" - -- id: convention_attribute_expected_name - msg: "expected convention name identifier in 'convention' attribute" - -- id: convention_attribute_expected_rparen - msg: "expected ')' after convention name for 'convention' attribute" - -- id: convention_attribute_ctype_expected_label - msg: "expected 'cType' label in 'convention' attribute" - -- id: convention_attribute_ctype_expected_colon - msg: "expected ':' after 'cType' for 'convention' attribute" - -- id: convention_attribute_ctype_expected_string - msg: "expected string literal containing clang type for 'cType' in 'convention' attribute" - -- id: convention_attribute_witness_method_expected_colon - msg: "expected ':' after 'witness_method' for 'convention' attribute" - -- id: convention_attribute_witness_method_expected_protocol - msg: "expected protocol name in 'witness_method' 'convention' attribute" - -- id: attr_objc_missing_colon - msg: "missing ':' after selector piece in @objc attribute" - -- id: attr_objc_expected_rparen - msg: "expected ')' after name for @objc" - -- id: attr_objc_empty_name - msg: "expected name within parentheses of @objc attribute" - -- id: attr_dynamic_replacement_expected_rparen - msg: "expected ')' after function name for @_dynamicReplacement" - -- id: attr_dynamic_replacement_expected_function - msg: "expected a function name in @_dynamicReplacement(for:)" - -- id: attr_dynamic_replacement_expected_for - msg: "expected 'for' in '_dynamicReplacement' attribute" - -- id: attr_dynamic_replacement_expected_colon - msg: "expected ':' after @_dynamicReplacement(for" - -- id: attr_type_eraser_expected_type_name - msg: "expected a type name in @_typeEraser()" - -- id: attr_type_eraser_expected_rparen - msg: "expected ')' after type name for @_typeEraser" - -- id: attr_private_import_expected_rparen - msg: "expected ')' after function name for @_private" - -- id: attr_private_import_expected_sourcefile - msg: "expected 'sourceFile' in '_private' attribute" - -- id: attr_private_import_expected_sourcefile_name - msg: "expected a source file name in @_private(sourceFile:)" - -- id: attr_private_import_expected_colon - msg: "expected ':' after @_private(sourceFile" - -- id: opened_attribute_expected_lparen - msg: "expected '(' after 'opened' attribute" - -- id: opened_attribute_id_value - msg: "known id for 'opened' attribute must be a UUID string" - -- id: opened_attribute_expected_rparen - msg: "expected ')' after id value for 'opened' attribute" - -- id: optimization_attribute_expect_option - msg: "expected '%0' option such as '%1'" - -- id: optimization_attribute_unknown_option - msg: "unknown option '%0' for attribute '%1'" - -- id: effects_attribute_expect_option - msg: "expected '%0' option (readnone, readonly, readwrite)" - -- id: effects_attribute_unknown_option - msg: "unknown option '%0' for attribute '%1'" - -- id: attr_unowned_invalid_specifier - msg: "expected 'safe' or 'unsafe'" - -- id: attr_unowned_expected_rparen - msg: "expected ')' after specifier for 'unowned'" - -- id: attr_warn_unused_result_removed - msg: "'warn_unused_result' attribute behavior is now the default" - -- id: attr_warn_unused_result_expected_rparen - msg: "expected ')' after 'warn_unused_result' attribute" - -- id: attr_specialize_missing_colon - msg: "missing ':' after %0 in '_specialize' attribute" - -- id: attr_specialize_missing_comma - msg: "missing ',' in '_specialize' attribute" - -- id: attr_specialize_unknown_parameter_name - msg: "unknown parameter %0 in '_specialize attribute'" - -- id: attr_specialize_expected_bool_value - msg: "expected a boolean true or false value in '_specialize' attribute" - -- id: attr_specialize_export_true_no_op - msg: "'exported: true' has no effect in '_specialize' attribute" - -- id: attr_specialize_missing_parameter_label_or_where_clause - msg: "expected a parameter label or a where clause in '_specialize' attribute" - -- id: attr_specialize_parameter_already_defined - msg: "parameter '%0' was already defined in '_specialize' attribute" - -- id: attr_specialize_expected_partial_or_full - msg: "expected 'partial' or 'full' as values of the 'kind' parameter in '_specialize' attribute" - -- id: attr_implements_expected_member_name - msg: "expected a member name as second parameter in '_implements' attribute" - -- id: attr_differentiable_expected_parameter_list - msg: "expected a list of parameters to differentiate with respect to" - -- id: attr_differentiable_use_wrt_not_withrespectto - msg: "use 'wrt:' to specify parameters to differentiate with respect to" - -- id: attr_differentiable_expected_label - msg: "expected 'wrt:' or 'where' in '@differentiable' attribute" - -- id: attr_differentiable_unexpected_argument - msg: "unexpected argument '%0' in '@differentiable' attribute" - -- id: expected_colon_after_label - msg: "expected a colon ':' after '%0'" - -- id: diff_params_clause_expected_parameter - msg: "expected a parameter, which can be a function parameter name, parameter index, or 'self'" - -- id: diff_params_clause_expected_parameter_unnamed - msg: "expected a parameter, which can be a function parameter index or 'self'" - -- id: autodiff_attr_expected_original_decl_name - msg: "expected an original function name" - -- id: sil_autodiff_expected_lsquare - msg: "expected '[' to start the %0" - -- id: sil_autodiff_expected_rsquare - msg: "expected ']' to complete the %0" - -- id: sil_autodiff_expected_index_list - msg: "expected a space-separated list of indices, e.g. '0 1'" - -- id: sil_autodiff_expected_index_list_label - msg: "expected label '%0' in index list" - -- id: sil_autodiff_expected_parameter_index - msg: "expected the index of a parameter to differentiate with respect to" - -- id: sil_autodiff_expected_result_index - msg: "expected the index of a result to differentiate from" - -- id: sil_inst_autodiff_operand_list_expected_lbrace - msg: "expected '{' to start a derivative function list" - -- id: sil_inst_autodiff_operand_list_expected_comma - msg: "expected ',' between operands in a derivative function list" - -- id: sil_inst_autodiff_operand_list_expected_rbrace - msg: "expected '}' to start a derivative function list" - -- id: sil_inst_autodiff_expected_differentiable_extractee_kind - msg: "expected an extractee kind attribute, which can be one of '[original]', '[jvp]', and '[vjp]'" - -- id: sil_inst_autodiff_expected_linear_extractee_kind - msg: "expected an extractee kind attribute, which can be one of '[original]' and '[transpose]'" - -- id: sil_inst_autodiff_expected_function_type_operand - msg: "expected an operand of a function type" - -- id: sil_inst_autodiff_expected_differentiability_witness_kind - msg: "expected a differentiability witness kind, which can be one of '[jvp]', '[vjp]', or '[transpose]'" - -- id: sil_inst_autodiff_invalid_witness_generic_signature - msg: "expected witness_generic signature '%0' does not have same generic parameters as original function generic signature '%1'" - -- id: expected_rangle_generics_param - msg: "expected '>' to complete generic parameter list" - -- id: expected_generics_parameter_name - msg: "expected an identifier to name generic parameter" - -- id: unexpected_class_constraint - msg: "'class' constraint can only appear on protocol declarations" - -- id: suggest_anyobject - msg: "did you mean to write an 'AnyObject' constraint?" - -- id: expected_generics_type_restriction - msg: "expected a class type or protocol-constrained type restricting %0" - -- id: requires_single_equal - msg: "use '==' for same-type requirements rather than '='" - -- id: requires_comma - msg: "expected ',' to separate the requirements of this 'where' clause" - -- id: expected_requirement_delim - msg: "expected ':' or '==' to indicate a conformance or same-type requirement" - -- id: redundant_class_requirement - msg: "redundant 'class' requirement" - -- id: late_class_requirement - msg: "'class' must come first in the requirement list" - -- id: where_inside_brackets - msg: "'where' clause next to generic parameters is obsolete, must be written following the declaration's type" - -- id: unsupported_conditional_compilation_binary_expression - msg: "expected '&&' or '||' expression" - -- id: unsupported_conditional_compilation_unary_expression - msg: "expected unary '!' expression" - -- id: unsupported_platform_condition_expression - msg: "unexpected platform condition (expected 'os', 'arch', or 'swift')" - -- id: platform_condition_expected_one_argument - msg: "expected only one argument to platform condition" - -- id: unsupported_platform_runtime_condition_argument - msg: "unexpected argument for the '_runtime' condition; expected '_Native' or '_ObjC'" - -- id: unsupported_platform_condition_argument - msg: "unexpected platform condition argument: expected %0" - -- id: unsupported_conditional_compilation_expression_type - msg: "invalid conditional compilation expression" - -- id: unsupported_conditional_compilation_integer - msg: "'%0' is not a valid conditional compilation expression, use '%1'" - -- id: version_component_not_number - msg: "version component contains non-numeric characters" - -- id: compiler_version_too_many_components - msg: "compiler version must not have more than five components" - -- id: unused_compiler_version_component - msg: "the second version component is not used for comparison" - -- id: empty_version_component - msg: "found empty version component" - -- id: compiler_version_component_out_of_range - msg: "compiler version component out of range: must be in [0, %0]" - -- id: empty_version_string - msg: "version requirement is empty" - -- id: unknown_platform_condition_argument - msg: "unknown %0 for build configuration '%1'" - -- id: renamed_platform_condition_argument - msg: "'%0' has been renamed to '%1'" - -- id: likely_simulator_platform_condition - msg: "platform condition appears to be testing for simulator environment; use 'targetEnvironment(simulator)' instead" - -- id: avail_query_expected_condition - msg: "expected availability condition" - -- id: avail_query_expected_platform_name - msg: "expected platform name" - -- id: avail_query_expected_version_number - msg: "expected version number" - -- id: avail_query_expected_rparen - msg: "expected ')' in availability query" - -- id: avail_query_unrecognized_platform_name - msg: "unrecognized platform name %0" - -- id: avail_query_disallowed_operator - msg: "'%0' cannot be used in an availability condition" - -- id: avail_query_argument_and_shorthand_mix_not_allowed - msg: "'%0' can't be combined with shorthand specification '%1'" - -- id: avail_query_meant_introduced - msg: "did you mean to specify an introduction version?" - -- id: avail_query_version_comparison_not_needed - msg: "version comparison not needed" - -- id: availability_query_wildcard_required - msg: "must handle potential future platforms with '*'" - -- id: availability_must_occur_alone - msg: "'%0' version-availability must be specified alone" - -- id: pound_available_swift_not_allowed - msg: "Swift language version checks not allowed in #available(...)" - -- id: pound_available_package_description_not_allowed - msg: "PackageDescription version checks not allowed in #available(...)" - -- id: availability_query_repeated_platform - msg: "version for '%0' already specified" - -- id: unknown_syntax_entity - msg: "unknown %0 syntax exists in the source" - -- id: expected_argument_label_followed_by_closure_literal - msg: "expected an argument label followed by a closure literal" - -- id: expected_closure_literal - msg: "expected a closure literal" - -- id: expected_multiple_closures_block_rbrace - msg: "expected '}' at the end of a trailing closures block" - -- id: decl_declared_here - msg: "%0 declared here" - -- id: kind_declared_here - msg: "%0 declared here" - -- id: implicit_member_declared_here - msg: "%1 '%0' is implicitly declared" - -- id: extended_type_declared_here - msg: "extended type declared here" - -- id: opaque_return_type_declared_here - msg: "opaque return type declared here" - -- id: ambiguous_member_overload_set - msg: "ambiguous reference to member %0" - -- id: ambiguous_reference_to_decl - msg: "ambiguous reference to %0 %1" - -- id: no_overloads_match_exactly_in_call - msg: "no exact matches in %select{reference|call}0 to %1 %select{%3|}2" - -- id: candidate_partial_match - msg: "candidate has partially matching parameter list %0" - -- id: could_not_find_value_subscript - msg: "value of type %0 has no subscripts" - -- id: could_not_find_tuple_member - msg: "value of tuple type %0 has no member %1" - -- id: could_not_find_value_member - msg: "value of type %0 has no member %1" - -- id: could_not_find_value_member_corrected - msg: "value of type %0 has no member %1; did you mean %2?" - -- id: could_not_find_value_dynamic_member_corrected - msg: "value of type %0 has no dynamic member %2 using key path from root type %1; did you mean %3?" - -- id: could_not_find_value_dynamic_member - msg: "value of type %0 has no dynamic member %2 using key path from root type %1" - -- id: cannot_infer_contextual_keypath_type_specify_root - msg: "cannot infer key path type from context; consider explicitly specifying a root type" - -- id: cannot_infer_keypath_root_anykeypath_context - msg: "'AnyKeyPath' does not provide enough context for root type to be inferred; consider explicitly specifying a root type" - -- id: could_not_find_type_member - msg: "type %0 has no member %1" - -- id: could_not_find_type_member_corrected - msg: "type %0 has no member %1; did you mean %2?" - -- id: could_not_find_subscript_member_did_you_mean - msg: "value of type %0 has no property or method named 'subscript'; did you mean to use the subscript operator?" - -- id: could_not_find_subscript_member_tuple - msg: "cannot access element using subscript for tuple type %0; use '.' notation instead" - -- id: could_not_find_subscript_member_tuple_did_you_mean_use_dot - msg: "cannot access element using subscript for tuple type %0; did you mean to use '.%1'?" - -- id: could_not_find_enum_case - msg: "enum type %0 has no case %1; did you mean %2?" - -- id: did_you_mean_raw_type - msg: "did you mean to specify a raw type on the enum declaration?" - -- id: did_you_mean_generic_param_as_conformance - msg: "did you mean to declare %0 as a protocol conformance for %1?" - -- id: any_as_anyobject_fixit - msg: "cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members" - -- id: expected_argument_in_contextual_member - msg: "member %0 expects argument of type %1" - -- id: expected_parens_in_contextual_member - msg: "member %0 is a function; did you mean to call it?" - -- id: expected_parens_in_contextual_member_type - msg: >- - member %0 is a function that produces expected type %1; did you mean to call it? - -- id: expected_result_in_contextual_member - msg: "member %0 in %2 produces result of type %1, but context expects %2" - -- id: unexpected_arguments_in_enum_case - msg: "enum case %0 has no associated values" - -- id: could_not_use_type_member_on_instance - msg: "static member %1 cannot be used on instance of type %0" - -- id: could_not_use_enum_element_on_instance - msg: "enum case %0 cannot be used as an instance member" - -- id: could_not_use_type_member_on_protocol_metatype - msg: "static member %1 cannot be used on protocol metatype %0" - -- id: could_not_use_instance_member_on_type - msg: "instance member %1%select{| of type %2}3 cannot be used on%select{| instance of nested}3 type %0" - -- id: could_not_use_member_on_existential - msg: "member %1 cannot be used on value of protocol type %0; use a generic constraint instead" - -- id: candidate_inaccessible - msg: "%0 is inaccessible due to '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level" - -- id: note_candidate_inaccessible - msg: "%0 is inaccessible due to '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level" - -- id: init_candidate_inaccessible - msg: "%0 initializer is inaccessible due to '%select{private|fileprivate|internal|@_spi|@_spi}1' protection level" - -- id: cannot_pass_rvalue_mutating_subelement - msg: "cannot use mutating member on immutable value: %0" - -- id: cannot_pass_rvalue_mutating - msg: "cannot use mutating member on immutable value of type %0" - -- id: cannot_pass_rvalue_mutating_getter_subelement - msg: "cannot use mutating getter on immutable value: %0" - -- id: cannot_pass_rvalue_mutating_getter - msg: "cannot use mutating getter on immutable value of type %0" - -- id: expression_too_complex - msg: "the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions" - -- id: value_type_comparison_with_nil_illegal_did_you_mean - msg: "value of type %0 cannot be compared by reference; did you mean to compare by value?" - -- id: value_type_comparison_with_nil_illegal - msg: "type %0 is not optional, value can never be nil" - -- id: cannot_match_expr_pattern_with_value - msg: "expression pattern of type %0 cannot match values of type %1" - -- id: cannot_match_expr_tuple_pattern_with_nontuple_value - msg: "tuple pattern cannot match values of non-tuple type %0" - -- id: cannot_match_unresolved_expr_pattern_with_value - msg: "pattern cannot match values of type %0" - -- id: cannot_reference_compare_types - msg: "cannot check reference equality of functions; operands here have types %1 and %2" - -- id: cannot_apply_binop_to_args - msg: "binary operator '%0' cannot be applied to operands of type %1 and %2" - -- id: cannot_apply_binop_to_same_args - msg: "binary operator '%0' cannot be applied to two %1 operands" - -- id: cannot_apply_unop_to_arg - msg: "unary operator '%0' cannot be applied to an operand of type %1" - -- id: cannot_apply_lvalue_unop_to_subelement - msg: "cannot pass immutable value to mutating operator: %0" - -- id: cannot_apply_lvalue_unop_to_rvalue - msg: "cannot pass immutable value of type %0 to mutating operator" - -- id: cannot_apply_lvalue_binop_to_subelement - msg: "left side of mutating operator isn't mutable: %0" - -- id: cannot_apply_lvalue_binop_to_rvalue - msg: "left side of mutating operator has immutable type %0" - -- id: cannot_subscript_base - msg: "cannot subscript a value of type %0" - -- id: cannot_subscript_ambiguous_base - msg: "cannot subscript a value of incorrect or ambiguous type" - -- id: cannot_subscript_nil_literal - msg: "cannot subscript a nil literal value" - -- id: conditional_cast_from_nil - msg: "nil literal cannot be the source of a conditional cast" - -- id: cannot_pass_rvalue_inout_subelement - msg: "cannot pass immutable value as inout argument: %0" - -- id: cannot_pass_rvalue_inout_converted - msg: "inout argument could be set to a value with a type other than %0; use a value declared as type %1 instead" - -- id: inout_change_var_type_if_possible - msg: "change variable type to %1 if it doesn't need to be declared as %0" - -- id: cannot_pass_rvalue_inout - msg: "cannot pass immutable value of type %0 as inout argument" - -- id: cannot_provide_default_value_inout - msg: "cannot provide default value to inout parameter %0" - -- id: cannot_call_with_params - msg: "cannot invoke %select{|initializer for type }2'%0' with an argument list of type '%1'" - -- id: cannot_call_non_function_value - msg: "cannot call value of non-function type %0" - -- id: no_candidates_match_result_type - msg: "no '%0' candidates produce the expected contextual result type %1" - -- id: no_candidates_match_argument_type - msg: "no '%0' candidates produce the expected type %1 for parameter #%2" - -- id: cannot_infer_closure_parameter_type - msg: "unable to infer type of a closure parameter %0 in the current context" - -- id: cannot_infer_closure_type - msg: "unable to infer closure type in the current context" - -- id: cannot_infer_closure_result_type - msg: "unable to infer%select{ complex|}0 closure return type; add explicit type to disambiguate" - -- id: incorrect_explicit_closure_result - msg: "declared closure result %0 is incompatible with contextual type %1" - -- id: suggest_expected_match - msg: "%select{expected an argument list|produces result}0 of type '%1'" - -- id: suggest_partial_overloads - msg: "overloads for '%1' exist with these %select{partially matching parameter lists|result types}0: %2" - -- id: no_binary_op_overload_for_enum_with_payload - msg: "binary operator '%0' cannot be synthesized for enums with associated values" - -- id: cannot_convert_initializer_value - msg: "cannot convert value of type %0 to specified type %1" - -- id: cannot_convert_initializer_value_protocol - msg: "value of type %0 does not conform to specified type %1" - -- id: cannot_convert_initializer_value_anyobject - msg: "value of type %0 expected to be instance of class or class-constrained type" - -- id: cannot_convert_initializer_value_nil - msg: "'nil' cannot initialize specified type %0" - -- id: cannot_convert_to_return_type - msg: "cannot convert return expression of type %0 to return type %1" - -- id: cannot_convert_to_return_type_protocol - msg: "return expression of type %0 does not conform to %1" - -- id: cannot_convert_return_type_to_anyobject - msg: "return expression of type %0 expected to be an instance of a class or class-constrained type" - -- id: cannot_convert_to_return_type_nil - msg: "'nil' is incompatible with return type %0" - -- id: cannot_convert_thrown_type - msg: "thrown expression type %0 does not conform to 'Error'" - -- id: cannot_throw_error_code - msg: "thrown error code type %0 does not conform to 'Error'; construct an %1 instance" - -- id: bad_yield_count - msg: "expected %0 yield value(s)" - -- id: cannot_throw_nil - msg: "cannot infer concrete Error for thrown 'nil' value" - -- id: cannot_convert_raw_initializer_value - msg: "cannot convert value of type %0 to raw type %1" - -- id: cannot_convert_raw_initializer_value_nil - msg: "cannot convert 'nil' to raw type %0" - -- id: cannot_convert_default_arg_value - msg: "default argument value of type %0 cannot be converted to type %1" - -- id: cannot_convert_default_arg_value_protocol - msg: "default argument value of type %0 does not conform to %1" - -- id: cannot_convert_default_arg_value_nil - msg: "nil default argument value cannot be converted to type %0" - -- id: cannot_convert_argument_value - msg: "cannot convert value of type %0 to expected argument type %1" - -- id: candidate_has_invalid_argument_at_position - msg: "candidate expects %select{|in-out }2value of type %0 for parameter #%1" - -- id: cannot_convert_array_to_variadic - msg: "cannot pass array of type %0 as variadic arguments of type %1" - -- id: candidate_would_match_array_to_variadic - msg: "candidate would match if array elements were passed as variadic arguments of type %0" - -- id: suggest_pass_elements_directly - msg: "remove brackets to pass array elements directly" - -- id: cannot_convert_argument_value_generic - msg: "cannot convert value of type %0 (%1) to expected argument type %2 (%3)" - -- id: conflicting_arguments_for_generic_parameter - msg: "conflicting arguments to generic parameter %0 (%1)" - -- id: cannot_pass_type_to_non_ephemeral - msg: "cannot pass %0 to parameter; argument %1 must be a pointer that outlives the call%select{| to %3}2" - -- id: cannot_pass_type_to_non_ephemeral_warning - msg: "passing %0 to parameter, but argument %1 should be a pointer that outlives the call%select{| to %3}2" - -- id: cannot_use_inout_non_ephemeral - msg: "cannot use inout expression here; argument %0 must be a pointer that outlives the call%select{| to %2}1" - -- id: cannot_use_inout_non_ephemeral_warning - msg: "inout expression creates a temporary pointer, but argument %0 should be a pointer that outlives the call%select{| to %2}1" - -- id: cannot_construct_dangling_pointer - msg: "initialization of %0 results in a dangling %select{|buffer }1pointer" - -- id: cannot_construct_dangling_pointer_warning - msg: "initialization of %0 results in a dangling %select{|buffer }1pointer" - -- id: ephemeral_pointer_argument_conversion_note - msg: "implicit argument conversion from %0 to %1 produces a pointer valid only for the duration of the call%select{| to %3}2" - -- id: ephemeral_use_with_unsafe_pointer - msg: "use 'withUnsafe%select{Bytes|MutableBytes|Pointer|MutablePointer}0' in order to explicitly convert argument to %select{buffer |buffer ||}0pointer valid for a defined scope" - -- id: ephemeral_use_string_with_c_string - msg: "use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope" - -- id: ephemeral_use_array_with_unsafe_buffer - msg: "use the 'withUnsafe%select{Bytes|MutableBytes|BufferPointer|MutableBufferPointer}0' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope" - -- id: candidate_performs_illegal_ephemeral_conv - msg: "candidate expects pointer that outlives the call for parameter #%0" - -- id: cannot_convert_argument_value_protocol - msg: "argument type %0 does not conform to expected type %1" - -- id: cannot_convert_argument_value_anyobject - msg: "argument type %0 expected to be an instance of a class or class-constrained type" - -- id: cannot_convert_argument_value_nil - msg: "'nil' is not compatible with expected argument type %0" - -- id: cannot_convert_condition_value - msg: "cannot convert value of type %0 to expected condition type %1" - -- id: cannot_convert_condition_value_nil - msg: "'nil' is not compatible with expected condition type %0" - -- id: cannot_yield_rvalue_by_reference_same_type - msg: "cannot yield immutable value of type %0 as an inout yield" - -- id: cannot_yield_rvalue_by_reference - msg: "cannot yield immutable value of type %0 as an inout yield of type %1" - -- id: cannot_yield_wrong_type_by_reference - msg: "cannot yield reference to storage of type %0 as an inout yield of type %1" - -- id: cannot_convert_yield_value - msg: "cannot convert value of type %0 to expected yield type %1" - -- id: cannot_convert_yield_value_protocol - msg: "yielded type %0 does not conform to expected type %1" - -- id: cannot_convert_yield_value_nil - msg: "nil is not compatible with expected yield type %0" - -- id: cannot_convert_closure_result - msg: "cannot convert value of type %0 to closure result type %1" - -- id: cannot_convert_closure_result_protocol - msg: "result value of type %0 does not conform to closure result type %1" - -- id: cannot_convert_closure_result_nil - msg: "'nil' is not compatible with closure result type %0" - -- id: cannot_convert_parent_type - msg: "cannot convert parent type %0 to expected type %1" - -- id: cannot_convert_chain_result_type - msg: >- - member chain produces result of type %0 but contextual base was inferred as %1 - -- id: generic_argument_mismatch - msg: "arguments to generic parameter %0 (%1 and %2) are expected to be equal" - -- id: destructor_not_accessible - msg: "deinitializers cannot be accessed" - -- id: cannot_convert_array_element - msg: "cannot convert value of type %0 to expected element type %1" - -- id: cannot_convert_array_element_protocol - msg: "value of type %0 does not conform to expected element type %1" - -- id: cannot_convert_array_element_nil - msg: "'nil' is not compatible with expected element type %0" - -- id: cannot_convert_dict_key - msg: "cannot convert value of type %0 to expected dictionary key type %1" - -- id: cannot_convert_dict_key_protocol - msg: "value of type %0 does not conform to expected dictionary key type %1" - -- id: cannot_convert_dict_key_nil - msg: "'nil' is not compatible with expected dictionary key type %0" - -- id: cannot_convert_dict_value - msg: "cannot convert value of type %0 to expected dictionary value type %1" - -- id: cannot_convert_dict_value_protocol - msg: "value of type %0 does not conform to expected dictionary value type %1" - -- id: cannot_convert_dict_value_nil - msg: "'nil' is not compatible with expected dictionary value type %0" - -- id: cannot_convert_coerce - msg: "cannot convert value of type %0 to type %1 in coercion" - -- id: cannot_convert_coerce_protocol - msg: "value of type %0 does not conform to %1 in coercion" - -- id: cannot_convert_coerce_nil - msg: "'nil' is not compatible with type %0 in coercion" - -- id: cannot_convert_assign - msg: "cannot assign value of type %0 to type %1" - -- id: assign_protocol_conformance_fix_it - msg: "add missing conformance to %0 to %1 %2" - -- id: cannot_convert_assign_protocol - msg: "value of type %0 does not conform to %1 in assignment" - -- id: cannot_convert_assign_anyobject - msg: "value of type %0 expected to be an instance of a class or class-constrained type in assignment" - -- id: cannot_convert_assign_nil - msg: "'nil' cannot be assigned to type %0" - -- id: cannot_convert_subscript_assign - msg: "cannot assign value of type %0 to subscript of type %1" - -- id: cannot_convert_subscript_assign_protocol - msg: "value of type %0 does not conform to %1 in subscript assignment" - -- id: cannot_convert_subscript_assign_nil - msg: "'nil' cannot be assigned to subscript of type %0" - -- id: cannot_convert_candidate_result_to_contextual_type - msg: "%0 produces %1, not the expected contextual result type %2" - -- id: cannot_convert_sequence_element_value - msg: "cannot convert sequence element type %0 to expected type %1" - -- id: cannot_convert_sequence_element_protocol - msg: "sequence element type %0 does not conform to expected protocol %1" - -- id: throws_functiontype_mismatch - msg: "invalid conversion from throwing function of type %0 to non-throwing function type %1" - -- id: expr_keypath_no_objc_runtime - msg: "'#keyPath' can only be used with the Objective-C runtime" - -- id: expression_unused_keypath_result - msg: "result of key path is unused" - -- id: expr_keypath_non_objc_property - msg: "argument of '#keyPath' refers to non-'@objc' property %0" - -- id: expr_keypath_swift3_objc_inference - msg: "argument of '#keyPath' refers to property %0 in %1 that depends on '@objc' inference deprecated in Swift 4" - -- id: expr_keypath_type_of_property - msg: "cannot refer to type member %0 within instance of type %1" - -- id: expr_keypath_generic_type - msg: "key path cannot refer to generic type %0" - -- id: expr_keypath_not_property - msg: "%select{key path|dynamic key path member lookup}2 cannot refer to %0 %1" - -- id: expr_keypath_mutating_getter - msg: "%select{key path|dynamic key path member lookup}1 cannot refer to %0, which has a mutating getter" - -- id: expr_keypath_static_member - msg: "%select{key path|dynamic key path member lookup}1 cannot refer to static member %0" - -- id: expr_keypath_enum_case - msg: "%select{key path|dynamic key path member lookup}1 cannot refer to enum case %0" - -- id: expr_keypath_empty - msg: "empty key path does not refer to a property" - -- id: expr_unsupported_objc_key_path_component - msg: "an Objective-C key path cannot contain %select{BAD|subscript|BAD|BAD|optional-forcing|optional-chaining|BAD} components" - -- id: expr_unsupported_objc_key_path_compound_name - msg: "an Objective-C key path cannot reference a declaration with a compound name" - -- id: expr_keypath_no_keypath_type - msg: "broken standard library: no 'KeyPath' type found" - -- id: expr_swift_keypath_invalid_component - msg: "invalid component of Swift key path" - -- id: expr_swift_keypath_not_starting_with_type - msg: "a Swift key path must begin with a type" - -- id: expr_swift_keypath_not_starting_with_dot - msg: "a Swift key path with contextual root must begin with a leading dot" - -- id: expr_smart_keypath_value_covert_to_contextual_type - msg: "key path value type %0 cannot be converted to contextual type %1" - -- id: expr_swift_keypath_empty - msg: "key path must have at least one component" - -- id: expr_string_interpolation_outside_string - msg: "string interpolation can only appear inside a string literal" - -- id: expr_keypath_subscript_index_not_hashable - msg: "subscript index of type %0 in a key path must be Hashable" - -- id: expr_smart_keypath_application_type_mismatch - msg: "key path of type %0 cannot be applied to a base of type %1" - -- id: expr_keypath_root_type_mismatch - msg: "key path with root type %0 cannot be applied to a base of type %1" - -- id: expr_swift_keypath_anyobject_root - msg: "the root type of a Swift key path cannot be 'AnyObject'" - -- id: expr_keypath_multiparam_func_conversion - msg: "cannot convert key path into a multi-argument function type %0" - -- id: expr_deprecated_writable_keypath - msg: "forming a writable keypath to property %0 that is read-only in this context is deprecated and will be removed in a future release" - -- id: expr_selector_no_objc_runtime - msg: "'#selector' can only be used with the Objective-C runtime" - -- id: expr_selector_module_missing - msg: "import the 'ObjectiveC' module to use '#selector'" - -- id: expr_selector_no_declaration - msg: "argument of '#selector' does not refer to an '@objc' method, property, or initializer" - -- id: expr_selector_not_method - msg: "argument of '#selector' cannot refer to %select{local|global}0 function %1" - -- id: expr_selector_expected_property - msg: "cannot reference %1 %2 as a property; remove '%select{getter|setter}0:'" - -- id: expr_selector_not_property - msg: "argument of '#selector' cannot refer to %select{variable|parameter}0 %1" - -- id: expr_selector_expected_method - msg: "use 'getter:'%select{| or 'setter:'}0 to refer to the Objective-C getter%select{| or setter}0 of property %1%select{|, respectively}0" - -- id: expr_selector_add_modifier - msg: "add '%select{getter|setter}0:' to reference the Objective-C %select{getter|setter}0 for %1" - -- id: expr_selector_property_not_settable - msg: "argument of '#selector(setter:)' refers to non-settable %0 %1" - -- id: expr_selector_property_setter_inaccessible - msg: "setter of %0 %1 is inaccessible" - -- id: expr_selector_cannot_be_used - msg: "cannot use %0 as a selector because protocol %1 is not exposed to Objective-C" - -- id: expr_selector_not_objc - msg: "argument of '#selector' refers to %0 %1 that is not exposed to Objective-C" - -- id: make_decl_objc - msg: "add '@objc' to expose this %0 to Objective-C" - -- id: expr_selector_swift3_objc_inference - msg: "argument of '#selector' refers to %0 %1 in %2 that depends on '@objc' inference deprecated in Swift 4" - -- id: selector_literal_invalid - msg: "string literal is not a valid Objective-C selector" - -- id: selector_literal_undeclared - msg: "no method declared with Objective-C selector %0" - -- id: selector_literal_deprecated - msg: "use of string literal for Objective-C selectors is deprecated; use '#selector' or explicitly construct a 'Selector'" - -- id: selector_literal_deprecated_suggest - msg: "use of string literal for Objective-C selectors is deprecated; use '#selector' instead" - -- id: selector_construction_suggest - msg: "use '#selector' instead of explicitly constructing a 'Selector'" - -- id: selector_construction_suppress_warning - msg: "wrap the selector name in parentheses to suppress this warning" - -- id: cannot_return_value_from_void_func - msg: "unexpected non-void return value in void function" - -- id: add_return_type_note - msg: "did you mean to add a return type?" - -- id: sema_no_import - msg: "no such module '%0'" - -- id: sema_no_import_target - msg: "could not find module '%0' for target '%1'; found: %2" - -- id: sema_no_import_repl - msg: "no such module '%0'" - -- id: sema_no_import_no_sdk - msg: "did you forget to set an SDK using -sdk or SDKROOT?" - -- id: sema_no_import_no_sdk_xcrun - msg: "use \"xcrun swiftc\" to select the default macOS SDK installed with Xcode" - -- id: sema_import_current_module - msg: "this file is part of module %0; ignoring import" - -- id: sema_import_current_module_with_file - msg: "file '%0' is part of module %1; ignoring import" - -- id: sema_opening_import - msg: "opening import file for module %0: %1" - -- id: serialization_load_failed - msg: "failed to load module '%0'" - -- id: module_interface_build_failed - msg: "failed to build module '%0' from its module interface; %select{the compiler that produced it, '%2', may have used features that aren't supported by this compiler, '%3'|it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced}1" - -- id: serialization_malformed_module - msg: "malformed compiled module: %0" - -- id: serialization_module_too_new - msg: "compiled module was created by a newer version of the compiler: %0" - -- id: serialization_module_language_version_mismatch - msg: "module compiled with Swift %0 cannot be imported by the Swift %1 compiler: %2" - -- id: serialization_module_too_old - msg: "compiled module was created by an older version of the compiler; rebuild %0 and try again: %1" - -- id: serialization_missing_single_dependency - msg: "missing required module '%0'" - -- id: serialization_missing_dependencies - msg: "missing required modules: %0" - -- id: serialization_circular_dependency - msg: "circular dependency between modules '%0' and %1" - -- id: serialization_missing_underlying_module - msg: "cannot load underlying module for %0" - -- id: serialization_name_mismatch - msg: "cannot load module '%0' as '%1'" - -- id: serialization_name_mismatch_repl - msg: "cannot load module '%0' as '%1'" - -- id: serialization_target_incompatible - msg: "module %0 was created for incompatible target %1: %2" - -- id: serialization_target_incompatible_repl - msg: "module %0 was created for incompatible target %1: %2" - -- id: serialization_target_too_new - msg: "compiling for %0 %1, but module %2 has a minimum deployment target of %0 %3: %4" - -- id: serialization_target_too_new_repl - msg: "compiling for %0 %1, but module %2 has a minimum deployment target of %0 %3: %4" - -- id: serialization_fatal - msg: "fatal error encountered while reading from module '%0'; please file a bug report with your project and the crash log" - -- id: serialization_misc_version - msg: "module '%0' full misc version is '%1'" - -- id: serialization_compatibility_version_mismatch - msg: "compiling as Swift %0, with '%1' built as Swift %2 (this is supported but may expose additional compiler issues)" - -- id: reserved_member_name - msg: "type member must not be named %0, since it would conflict with the 'foo.%1' expression" - -- id: invalid_redecl - msg: "invalid redeclaration of %0" - -- id: invalid_redecl_init - msg: "invalid redeclaration of synthesized %select{|memberwise }1%0" - -- id: invalid_redecl_implicit - msg: "invalid redeclaration of synthesized %select{%0|implementation for protocol requirement}1 %2" - -- id: invalid_redecl_swift5_warning - msg: "redeclaration of %0 is deprecated and will be an error in Swift 5" - -- id: invalid_redecl_prev - msg: "%0 previously declared here" - -- id: invalid_redecl_implicit_wrapper - msg: "%0 synthesized for property wrapper %select{projected value|backing storage}1" - -- id: ambiguous_type_base - msg: "%0 is ambiguous for type lookup in this context" - -- id: invalid_member_type - msg: "%0 is not a member type of %1" - -- id: invalid_member_type_suggest - msg: "%0 does not have a member type named %1; did you mean %2?" - -- id: invalid_member_reference - msg: "%0 %1 is not a member type of %2" - -- id: ambiguous_member_type - msg: "ambiguous type name %0 in %1" - -- id: no_module_type - msg: "no type named %0 in module %1" - -- id: ambiguous_module_type - msg: "ambiguous type name %0 in module %1" - -- id: use_nonmatching_operator - msg: "%0 is not a %select{binary|prefix unary|postfix unary}1 operator" - -- id: unsupported_recursion_in_associated_type_reference - msg: "unsupported recursion for reference to %select{associated type|type alias}0 %1 of type %2" - -- id: broken_associated_type_witness - msg: "reference to invalid %select{associated type|type alias}0 %1 of type %2" - -- id: unspaced_binary_operator_fixit - msg: "missing whitespace between %0 and %1 operators" - -- id: unspaced_binary_operator - msg: "ambiguous missing whitespace between unary and binary operators" - -- id: unspaced_binary_operators_candidate - msg: "could be %select{binary|postfix}2 %0 and %select{prefix|binary}2 %1" - -- id: unspaced_unary_operator - msg: "unary operators must not be juxtaposed; parenthesize inner expression" - -- id: cannot_find_in_scope - msg: "cannot %select{find|find operator}1 %0 in scope" - -- id: cannot_find_in_scope_corrected - msg: "cannot %select{find|find operator}1 %0 in scope; did you mean '%2'?" - -- id: confusable_character - msg: "%select{identifier|operator}0 '%1' contains possibly confused characters; did you mean to use '%2'?" - -- id: single_confusable_character - msg: "%select{identifier|operator}0 '%1' (%2) looks similar to '%3' (%4); did you mean '%3' (%4)?" - -- id: cannot_find_type_in_scope - msg: "cannot find type %0 in scope" - -- id: cannot_find_type_in_scope_did_you_mean - msg: "cannot find type %0 in scope; did you mean to use '%1'?" - -- id: note_typo_candidate_implicit_member - msg: "did you mean the implicitly-synthesized %1 '%0'?" - -- id: note_remapped_type - msg: "did you mean to use '%0'?" - -- id: note_module_as_type - msg: "cannot use module %0 as a type" - -- id: use_unknown_object_literal_protocol - msg: "cannot deduce protocol for %0 literal" - -- id: object_literal_default_type_missing - msg: "could not infer type of %0 literal" - -- id: object_literal_resolve_import - msg: "import %0 to use '%1' as the default %2 literal type" - -- id: use_local_before_declaration - msg: "use of local variable %0 before its declaration" - -- id: unsupported_existential_type - msg: "protocol %0 can only be used as a generic constraint because it has Self or associated type requirements" - -- id: decl_does_not_exist_in_module - msg: "%select{%error|type|struct|class|enum|protocol|variable|function}0 %1 does not exist in module %2" - -- id: imported_decl_is_wrong_kind - msg: "%0 was imported as '%1', but is %select{%error|a type|a struct|a class|an enum|a protocol|a variable|a function}2" - -- id: imported_decl_is_wrong_kind_typealias - msg: "%0 %1 cannot be imported as '%2'" - -- id: ambiguous_decl_in_module - msg: "ambiguous name %0 in module %1" - -- id: module_not_testable - msg: "module %0 was not compiled for testing" - -- id: module_not_compiled_for_private_import - msg: "module %0 was not compiled for private import" - -- id: import_implementation_cannot_be_exported - msg: "module %0 cannot be both exported and implementation-only" - -- id: module_not_compiled_with_library_evolution - msg: "module %0 was not compiled with library evolution support; using it means binary compatibility for %1 can't be guaranteed" - -- id: cross_import_added - msg: "import of %0 and %1 triggered a cross-import of %2" - -- id: ambiguous_operator_decls - msg: "ambiguous operator declarations found for operator" - -- id: found_this_operator_decl - msg: "found this matching operator declaration" - -- id: operator_redeclared - msg: "operator redeclared" - -- id: previous_operator_decl - msg: "previous operator declaration here" - -- id: declared_operator_without_operator_decl - msg: "operator implementation without matching operator declaration" - -- id: declared_unary_op_without_attribute - msg: "unary operator implementation must have a 'prefix' or 'postfix' modifier" - -- id: unary_op_missing_prepos_attribute - msg: "%select{prefix|postfix}0 unary operator missing '%select{prefix|postfix}0' modifier" - -- id: unary_operator_declaration_here - msg: "%select{prefix|postfix}0 operator found here" - -- id: invalid_arg_count_for_operator - msg: "operators must have one or two arguments" - -- id: operator_in_local_scope - msg: "operator functions can only be declared at global or in type scope" - -- id: nonstatic_operator_in_nominal - msg: "operator %0 declared in type %1 must be 'static'" - -- id: nonstatic_operator_in_extension - msg: "operator %0 declared in extension%select{| of %2}1 must be 'static'" - -- id: nonfinal_operator_in_class - msg: "operator %0 declared in non-final class %1 must be 'final'" - -- id: operator_in_unrelated_type - msg: "member operator %2%select{| of protocol %0}1 must have at least one argument of type %select{%0|'Self'}1" - -- id: ambiguous_precedence_groups - msg: "multiple precedence groups found" - -- id: found_this_precedence_group - msg: "found this matching precedence group" - -- id: unknown_precedence_group - msg: "unknown precedence group %0" - -- id: precedence_group_cycle - msg: "cycle in '%select{lowerThan|higherThan}0' relation" - -- id: higher_than_precedence_group_cycle - msg: "cycle in higherThan relation: %0" - -- id: precedence_group_lower_within_module - msg: "precedence group cannot be given lower precedence than group in same module; make the other precedence group higher than this one instead" - -- id: precedence_group_redeclared - msg: "precedence group redeclared" - -- id: previous_precedence_group_decl - msg: "previous precedence group declaration here" - -- id: circular_reference_through_precedence_group - msg: "through reference to precedence group %0 here" - -- id: tuple_types_not_convertible_nelts - msg: "%0 is not convertible to %1, tuples have a different number of elements" - -- id: tuple_types_not_convertible - msg: "tuple type %0 is not convertible to tuple type %1" - -- id: invalid_force_unwrap - msg: "cannot force unwrap value of non-optional type %0" - -- id: invalid_optional_chain - msg: "cannot use optional chaining on non-optional value of type %0" - -- id: if_expr_cases_mismatch - msg: "result values in '? :' expression have mismatching types %0 and %1" - -- id: did_not_call_function_value - msg: "function value was used as a property; add () to call it" - -- id: did_not_call_function - msg: "function %0 was used as a property; add () to call it" - -- id: did_not_call_method - msg: "method %0 was used as a property; add () to call it" - -- id: init_not_instance_member_use_assignment - msg: "'init' is a member of the type; use assignment to initalize the value instead" - -- id: init_not_instance_member - msg: "'init' is a member of the type; use 'type(of: ...)' to initialize a new object of the same dynamic type" - -- id: super_initializer_not_in_initializer - msg: "'super.init' cannot be called outside of an initializer" - -- id: isa_is_always_true - msg: "'%0' test is always true" - -- id: isa_is_foreign_check - msg: "'is' test is always true because %0 is a Core Foundation type" - -- id: conditional_downcast_coercion - msg: "conditional cast from %0 to %1 always succeeds" - -- id: literal_conditional_downcast_to_coercion - msg: "conditional downcast from literal to %0 always fails; consider using 'as' coercion" - -- id: forced_downcast_noop - msg: "forced cast of %0 to same type has no effect" - -- id: forced_downcast_coercion - msg: "forced cast from %0 to %1 always succeeds; did you mean to use 'as'?" - -- id: downcast_same_type - msg: "forced cast from %0 to %1 %select{only unwraps optionals|only unwraps and bridges}3; did you mean to use '%2'%select{| with 'as'}3?" - -- id: conditional_downcast_same_type - msg: "conditional downcast from %0 to %1 %select{does nothing|is equivalent to an implicit conversion to an optional %1|is a bridging conversion; did you mean to use 'as'?}2" - -- id: is_expr_same_type - msg: "checking a value with optional type %0 against dynamic type %1 succeeds whenever the value is non-nil; did you mean to use '!= nil'?" - -- id: downcast_to_unrelated - msg: "cast from %0 to unrelated type %1 always fails" - -- id: downcast_to_unrelated_fixit - msg: "did you mean to call %0 with '()'?" - -- id: downcast_to_more_optional - msg: "cannot downcast from %0 to a more optional type %1" - -- id: optional_chain_noop - msg: "optional chain has no effect, expression already produces %0" - -- id: optional_chain_isnt_chaining - msg: "'?' must be followed by a call, member lookup, or subscript" - -- id: pattern_in_expr - msg: "%0 cannot appear in an expression" - -- id: note_call_to_operator - msg: "in call to operator %0" - -- id: note_call_to_func - msg: "in call to function %0" - -- id: note_call_to_subscript - msg: "in call to %0" - -- id: note_call_to_initializer - msg: "in call to initializer" - -- id: note_init_parameter - msg: "in initialization of parameter %0" - -- id: missing_nullary_call - msg: "function produces expected type %0; did you mean to call it with '()'?" - -- id: optional_not_unwrapped - msg: "value of optional type %0 must be unwrapped to a value of type %1" - -- id: unwrap_with_default_value - msg: "coalesce using '??' to provide a default when the optional value contains 'nil'" - -- id: unwrap_with_force_value - msg: "force-unwrap using '!' to abort execution if the optional value contains 'nil'" - -- id: unwrap_iuo_initializer - msg: "value inferred to be type %0 when initialized with an implicitly unwrapped value" - -- id: unwrap_with_guard - msg: "short-circuit using 'guard' to exit this function early if the optional value contains 'nil'" - -- id: optional_base_not_unwrapped - msg: "value of optional type %0 must be unwrapped to refer to member %1 of wrapped base type %2" - -- id: invalid_optional_infered_keypath_root - msg: "key path root inferred as optional type %0 must be unwrapped to refer to member %1 of unwrapped type %2" - -- id: optional_base_chain - msg: "chain the optional using '?' to access member %0 only for non-'nil' base values" - -- id: optional_base_remove_optional_for_keypath_root - msg: "use unwrapped type %0 as key path root" - -- id: optional_keypath_application_base - msg: "use '?' to access key path subscript only for non-'nil' base values" - -- id: optional_key_path_root_base_chain - msg: "chain the optional using '?.' to access unwrapped type member %0" - -- id: optional_key_path_root_base_unwrap - msg: "unwrap the optional using '!.' to access unwrapped type member %0" - -- id: missing_unwrap_optional_try - msg: "value of optional type %0 not unwrapped; did you mean to use 'try!' or chain with '?'?" - -- id: missing_forced_downcast - msg: "%0 is not convertible to %1; did you mean to use 'as!' to force downcast?" - -- id: coercion_may_fail_warning - msg: "coercion from %0 to %1 may fail; use 'as?' or 'as!' instead" - -- id: missing_explicit_conversion - msg: "%0 is not implicitly convertible to %1; did you mean to use 'as' to explicitly convert?" - -- id: missing_address_of - msg: "passing value of type %0 to an inout parameter requires explicit '&'" - -- id: missing_address_of_yield - msg: "yielding mutable value of type %0 requires explicit '&'" - -- id: extraneous_address_of - msg: "use of extraneous '&'" - -- id: extra_address_of - msg: "'&' used with non-inout argument of type %0" - -- id: extra_address_of_unsafepointer - msg: "'&' is not allowed passing array value as %0 argument" - -- id: cannot_pass_inout_arg_to_subscript - msg: "cannot pass an inout argument to a subscript; use 'withUnsafeMutablePointer' to explicitly convert argument to a pointer" - -- id: incorrect_property_wrapper_reference - msg: "cannot convert value %0 of type %1 to expected type %2, use %select{wrapper|wrapped value}3 instead" - -- id: incorrect_property_wrapper_reference_member - msg: "referencing %0 %1 requires %select{wrapper|wrapped value of type}2 %3" - -- id: missing_init_on_metatype_initialization - msg: "initializing from a metatype value must reference 'init' explicitly" - -- id: extra_argument_labels - msg: "extraneous argument label%select{|s}0 '%1' in %select{call|subscript}2" - -- id: missing_argument_labels - msg: "missing argument label%select{|s}0 '%1' in %select{call|subscript}2" - -- id: wrong_argument_labels - msg: "incorrect argument label%select{|s}0 in %select{call|subscript}3 (have '%1', expected '%2')" - -- id: argument_out_of_order_named_named - msg: "argument %0 must precede argument %1" - -- id: argument_out_of_order_named_unnamed - msg: "argument %0 must precede unnamed argument #%1" - -- id: argument_out_of_order_unnamed_named - msg: "unnamed argument #%0 must precede argument %1" - -- id: argument_out_of_order_unnamed_unnamed - msg: "unnamed argument #%0 must precede unnamed argument #%1" - -- id: argument_out_of_order_binary_op - msg: "operator argument #%0 must precede operator argument #%1" - -- id: candidate_expected_different_labels - msg: "incorrect labels for candidate (have: '%0', expected: '%1')" - -- id: member_shadows_function - msg: "use of %0 refers to %1 rather than %2 %3" - -- id: member_shadows_global_function - msg: "use of %0 refers to %1 rather than %2 %3 in module %4" - -- id: instance_member_use_on_type - msg: "instance member %1 cannot be used on type %0; did you mean to use a value of this type instead?" - -- id: instance_member_in_initializer - msg: "cannot use instance member %0 within property initializer; property initializers run before 'self' is available" - -- id: instance_member_in_default_parameter - msg: "cannot use instance member %0 as a default parameter" - -- id: missing_argument_named - msg: "missing argument for parameter %0 in call" - -- id: missing_argument_positional - msg: "missing argument for parameter #%0 in call" - -- id: missing_arguments_in_call - msg: "missing arguments for parameters %0 in call" - -- id: extra_argument_named - msg: "extra argument %0 in call" - -- id: extra_argument_positional - msg: "extra argument in call" - -- id: extra_arguments_in_call - msg: "extra arguments at positions %0 in call" - -- id: extra_argument_to_nullary_call - msg: "argument passed to call that takes no arguments" - -- id: extra_trailing_closure_in_call - msg: "extra trailing closure passed in call" - -- id: trailing_closure_bad_param - msg: "trailing closure passed to parameter of type %0 that does not accept a closure" - -- id: unlabeled_trailing_closure_deprecated - msg: "backward matching of the unlabeled trailing closure is deprecated; label the argument with %0 to suppress this warning" - -- id: decl_multiple_defaulted_closure_parameters - msg: "%0 contains defaulted closure parameters %1 and %2" - -- id: candidate_with_extraneous_args - msg: "candidate %0 requires %1 argument%s1, but %2 %select{were|was}3 %select{provided|used in closure body}4" - -- id: no_accessible_initializers - msg: "%0 cannot be constructed because it has no accessible initializers" - -- id: non_nominal_no_initializers - msg: "non-nominal type %0 does not support explicit initialization" - -- id: unbound_generic_parameter - msg: "generic parameter %0 could not be inferred" - -- id: unbound_generic_parameter_cast - msg: "generic parameter %0 could not be inferred in cast to %1" - -- id: archetype_declared_in_type - msg: "%0 declared as parameter to type %1" - -- id: unbound_generic_parameter_explicit_fix - msg: "explicitly specify the generic arguments to fix this issue" - -- id: invalid_dynamic_callable_type - msg: "@dynamicCallable attribute requires %0 to have either a valid 'dynamicallyCall(withArguments:)' method or 'dynamicallyCall(withKeywordArguments:)' method" - -- id: missing_dynamic_callable_kwargs_method - msg: "@dynamicCallable type %0 cannot be applied with keyword arguments; missing 'dynamicCall(withKeywordArguments:)' method" - -- id: invalid_dynamic_member_lookup_type - msg: "@dynamicMemberLookup attribute requires %0 to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path" - -- id: invalid_dynamic_member_subscript - msg: "add an explicit argument label to this subscript to satisfy the @dynamicMemberLookup requirement" - -- id: string_index_not_integer - msg: "String must not be indexed with %0, it has variable size elements" - -- id: string_index_not_integer_note - msg: "consider using an existing high level algorithm, str.startIndex.advanced(by: n), or a projection like str.utf8" - -- id: invalid_c_function_pointer_conversion_expr - msg: "a C function pointer can only be formed from a reference to a 'func' or a literal closure" - -- id: c_function_pointer_from_method - msg: "a C function pointer cannot be formed from a method" - -- id: c_function_pointer_from_generic_function - msg: "a C function pointer cannot be formed from a reference to a generic function" - -- id: unsupported_linear_to_differentiable_conversion - msg: "conversion from '@differentiable(linear)' to '@differentiable' is not yet supported" - -- id: invalid_autoclosure_forwarding - msg: "add () to forward @autoclosure parameter" - -- id: invalid_differentiable_function_conversion_expr - msg: "a '@differentiable%select{|(linear)}0' function can only be formed from a reference to a 'func' or 'init' or a literal closure" - -- id: invalid_differentiable_function_conversion_parameter - msg: "did you mean to take a '%0' closure?" - -- id: invalid_autoclosure_pointer_conversion - msg: "cannot perform pointer conversion of value of type %0 to autoclosure result type %1" - -- id: missing_initializer_def - msg: "initializer requires a body" - -- id: pound_warning - msg: "%0" - -- id: pound_error - msg: "%0" - -- id: operator_not_func - msg: "operators must be declared with 'func'" - -- id: redefining_builtin_operator - msg: "cannot declare a custom %0 '%1' operator" - -- id: attribute_requires_operator_identifier - msg: "'%0' requires a function with an operator identifier" - -- id: attribute_requires_single_argument - msg: "'%0' requires a function with one argument" - -- id: nominal_type_not_attribute - msg: "%0 %1 cannot be used as an attribute" - -- id: mutating_invalid_global_scope - msg: "%0 is only valid on methods" - -- id: mutating_invalid_classes - msg: "%0 is not valid on %1s in %select{classes|class-bound protocols}2" - -- id: functions_mutating_and_not - msg: "method must not be declared both %0 and %1" - -- id: static_functions_not_mutating - msg: "static functions must not be declared mutating" - -- id: modify_mutatingness_differs_from_setter - msg: "'modify' accessor cannot be %0 when the setter is %1" - -- id: transparent_in_protocols_not_supported - msg: "'@_transparent' attribute is not supported on declarations within protocols" - -- id: transparent_in_classes_not_supported - msg: "'@_transparent' attribute is not supported on declarations within classes" - -- id: invalid_iboutlet - msg: "only instance properties can be declared @IBOutlet" - -- id: iboutlet_nonobjc_class - msg: "@IBOutlet property cannot %select{have|be an array of}0 non-'@objc' class type %1" - -- id: iboutlet_nonobjc_protocol - msg: "@IBOutlet property cannot %select{have|be an array of}0 non-'@objc' protocol type %1" - -- id: iboutlet_nonobject_type - msg: "@IBOutlet property cannot %select{have|be an array of}0 non-object type %1" - -- id: iboutlet_only_mutable - msg: "@IBOutlet attribute requires property to be mutable" - -- id: iboutlet_non_optional - msg: "@IBOutlet property has non-optional type %0" - -- id: note_make_optional - msg: "add '?' to form the optional type %0" - -- id: note_make_implicitly_unwrapped_optional - msg: "add '!' to form an implicitly unwrapped optional" - -- id: invalid_ibdesignable_extension - msg: "@IBDesignable can only be applied to classes and extensions of classes" - -- id: invalid_ibinspectable - msg: "only instance properties can be declared @%0" - -- id: invalid_ibaction_decl - msg: "only instance methods can be declared @%0" - -- id: invalid_ibaction_result - msg: "methods declared @%0 must %select{|not }1return a value" - -- id: invalid_ibaction_argument_count - msg: "@%0 methods must have %1 to %2 arguments" - -- id: invalid_ibaction_argument_count_exact - msg: "@%0 methods must have %2 argument%s2" - -- id: invalid_ibaction_argument_count_max - msg: "@%0 methods must have at most %2 argument%s2" - -- id: ibsegueaction_objc_method_family - msg: "@%0 method cannot have selector %1 because it has special memory management behavior" - -- id: fixit_rename_in_swift - msg: "change Swift name to %0" - -- id: fixit_rename_in_objc - msg: "change Objective-C selector to %0" - -- id: no_objc_tagged_pointer_not_class_protocol - msg: "@unsafe_no_objc_tagged_pointer can only be applied to class protocols" - -- id: swift_native_objc_runtime_base_not_on_root_class - msg: "@_swift_native_objc_runtime_base_not_on_root_class can only be applied to root classes" - -- id: cdecl_not_at_top_level - msg: "@_cdecl can only be applied to global functions" - -- id: cdecl_empty_name - msg: "@_cdecl symbol name cannot be empty" - -- id: cdecl_throws - msg: "raising errors from @_cdecl functions is not supported" - -- id: attr_methods_only - msg: "only methods can be declared %0" - -- id: access_control_in_protocol - msg: "%0 modifier cannot be used in protocols" - -- id: access_control_in_protocol_detail - msg: "protocol requirements implicitly have the same access as the protocol itself" - -- id: access_control_setter - msg: "'%select{private|fileprivate|internal|public|open}0(set)' modifier can only be applied to variables and subscripts" - -- id: access_control_setter_read_only - msg: "'%select{private|fileprivate|internal|public|%error}0(set)' modifier cannot be applied to %select{constants|read-only variables|read-only properties|read-only subscripts}1" - -- id: access_control_setter_more - msg: "%select{private|fileprivate|internal|public|%error}0 %select{variable|property|subscript}1 cannot have %select{%error|a fileprivate|an internal|a public|an open}2 setter" - -- id: access_control_setter_redundant - msg: "'%select{private|fileprivate|internal|public|open}0(set)' modifier is redundant for %select{a private|a fileprivate|an internal|a public|an open}2 %1" - -- id: access_control_ext_member_more - msg: "'%select{%error|fileprivate|internal|public|open}0' modifier conflicts with extension's default access of '%select{private|fileprivate|internal|public|%error}1'" - -- id: access_control_ext_member_redundant - msg: "'%select{%error|fileprivate|internal|public|%error}0' modifier is redundant for %1 declared in %select{a private (equivalent to fileprivate)|a fileprivate|an internal|a public|%error}2 extension" - -- id: access_control_ext_requirement_member_more - msg: "cannot declare %select{%error|a fileprivate|an internal|a public|an open}0 %1 in an extension with %select{private|fileprivate|internal|public|%error}2 requirements" - -- id: access_control_extension_more - msg: "extension of %select{private|fileprivate|internal|%error|%error}0 %1 cannot be declared %select{%error|fileprivate|internal|public|%error}2" - -- id: access_control_extension_open - msg: "extensions cannot use 'open' as their default access; use 'public'" - -- id: access_control_open_bad_decl - msg: "only classes and overridable class members can be declared 'open'; use 'public'" - -- id: invalid_decl_attribute - msg: "'%0' attribute cannot be applied to this declaration" - -- id: invalid_decl_modifier - msg: "%0 modifier cannot be applied to this declaration" - -- id: attribute_does_not_apply_to_type - msg: "attribute does not apply to type" - -- id: optional_attribute_non_protocol - msg: "'optional' can only be applied to protocol members" - -- id: optional_attribute_non_objc_protocol - msg: "'optional' can only be applied to members of an @objc protocol" - -- id: optional_attribute_missing_explicit_objc - msg: "'optional' requirements are an Objective-C compatibility feature; add '@objc'" - -- id: objcmembers_attribute_nonclass - msg: "'@objcMembers' attribute can only be applied to a class" - -- id: optional_attribute_initializer - msg: "'optional' cannot be applied to an initializer" - -- id: unavailable_method_non_objc_protocol - msg: "protocol members can only be marked unavailable in an @objc protocol" - -- id: missing_in_class_init_1 - msg: "stored property %0 requires an initial value%select{| or should be @NSManaged}1" - -- id: missing_in_class_init_2 - msg: "stored properties %0 and %1 require initial values%select{| or should be @NSManaged}2" - -- id: missing_in_class_init_3plus - msg: "stored properties %0, %1, %select{and %2|%2, and others}3 require initial values%select{| or should be @NSManaged}4" - -- id: requires_stored_property_inits_here - msg: "%select{superclass|class}1 %0 requires all stored properties to have initial values%select{| or use @NSManaged}2" - -- id: class_without_init - msg: "class %0 has no initializers" - -- id: note_no_in_class_init_1 - msg: "stored property %0 without initial value prevents synthesized initializers" - -- id: note_no_in_class_init_2 - msg: "stored properties %0 and %1 without initial values prevent synthesized initializers" - -- id: note_no_in_class_init_3plus - msg: "stored properties %0, %1, %select{and %2|%2, and others}3 without initial values prevent synthesized initializers" - -- id: missing_unimplemented_init_runtime - msg: "standard library error: missing _unimplementedInitializer" - -- id: missing_undefined_runtime - msg: "standard library error: missing _undefined" - -- id: expr_dynamic_lookup_swift3_objc_inference - msg: "reference to %0 %1 of %2 depends on '@objc' inference deprecated in Swift 4" - -- id: inherited_default_value_not_in_designated_constructor - msg: "default value inheritance via 'super' is only valid on the parameters of designated initializers" - -- id: inherited_default_value_used_in_non_overriding_constructor - msg: "default value inheritance via 'super' can only be used when overriding a designated initializer" - -- id: corresponding_param_not_defaulted - msg: "default value inheritance via 'super' requires that the corresponding parameter of the overridden designated initializer has a default value" - -- id: inherited_default_param_here - msg: "corresponding parameter declared here" - -- id: option_set_zero_constant - msg: "static property %0 produces an empty option set" - -- id: option_set_empty_set_init - msg: "use [] to silence this warning" - -- id: originally_defined_in_dupe_platform - msg: "duplicate version number for platform %0" - -- id: originally_definedin_topleve_decl - msg: "@%0 is only applicable to top-level decl" - -- id: originally_definedin_need_available - msg: "need @available attribute for @%0" - -- id: originally_definedin_must_after_available_version - msg: "moved version from @%0 must after introduced OS version" - -- id: alignment_not_power_of_two - msg: "alignment value must be a power of two" - -- id: indirect_case_without_payload - msg: "enum case %0 without associated value cannot be 'indirect'" - -- id: indirect_case_in_indirect_enum - msg: "enum case in 'indirect' enum cannot also be 'indirect'" - -- id: enum_frozen_nonpublic - msg: "%0 has no effect on non-public enums" - -- id: getset_init - msg: "variable with getter/setter cannot have an initial value" - -- id: unimplemented_static_var - msg: "%select{ERROR|static|class}1 stored properties not supported%select{ in this context| in generic types| in classes| in protocol extensions}0%select{|; did you mean 'static'?}2" - -- id: observingprop_requires_initializer - msg: "non-member observing properties require an initializer" - -- id: global_requires_initializer - msg: "global '%select{var|let}0' declaration requires an initializer expression%select{ or getter/setter specifier|}0" - -- id: static_requires_initializer - msg: "%select{ERROR|'static var'|'class var'|}0 declaration requires an initializer expression or getter/setter specifier" - -- id: pattern_type_access - msg: "%select{%select{variable|constant}0|property}1 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - -- id: pattern_type_access_warn - msg: "%select{%select{variable|constant}0|property}1 %select{should be declared %select{private|fileprivate|internal|%error|%error}5|should not be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - -- id: pattern_type_access_inferred - msg: "%select{%select{variable|constant}0|property}1 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type %6 uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - -- id: pattern_type_access_inferred_warn - msg: "%select{%select{variable|constant}0|property}1 %select{should be declared %select{private|fileprivate|internal|%error|%error}5|should not be declared %select{in this context|fileprivate|internal|public|open}3}2 because its type %6 uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - -- id: pattern_type_not_usable_from_inline - msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 must be '@usableFromInline' or public" - -- id: pattern_type_not_usable_from_inline_warn - msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 should be '@usableFromInline' or public" - -- id: pattern_type_not_usable_from_inline_frozen - msg: "type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public" - -- id: pattern_type_not_usable_from_inline_inferred - msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 with inferred type %2 must be '@usableFromInline' or public" - -- id: pattern_type_not_usable_from_inline_inferred_warn - msg: "type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 with inferred type %2 should be '@usableFromInline' or public" - -- id: pattern_type_not_usable_from_inline_inferred_frozen - msg: "type referenced from a stored property with inferred type %2 in a '@frozen' struct must be '@usableFromInline' or public" - -- id: pattern_binds_no_variables - msg: "%select{property|global variable}0 declaration does not bind any variables" - -- id: variable_bound_by_no_pattern - msg: "variable %0 is not bound by any pattern" - -- id: optional_ambiguous_case_ref - msg: "assuming you mean '%0.%2'; did you mean '%1.%2' instead?" - -- id: optional_fixit_ambiguous_case_ref - msg: "explicitly specify 'Optional' to silence this warning" - -- id: optional_fixit_ambiguous_case_ref_switch - msg: "use 'nil' to silence this warning" - -- id: type_fixit_optional_ambiguous_case_ref - msg: "use '%0.%1' instead" - -- id: type_fixit_optional_ambiguous_case_ref_switch - msg: "use '%0' instead" - -- id: nscoding_unstable_mangled_name - msg: "%select{private|fileprivate|nested|local}0 class %1 has an unstable name when archiving via 'NSCoding'" - -- id: unstable_mangled_name_add_objc_new - msg: "for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name" - -- id: unstable_mangled_name_add_objc - msg: "for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name" - -- id: unsupported_type_nested_in_generic_function - msg: "type %0 cannot be nested in generic function %1" - -- id: unsupported_type_nested_in_generic_closure - msg: "type %0 cannot be nested in closure in generic context" - -- id: unsupported_type_nested_in_protocol - msg: "type %0 cannot be nested in protocol %1" - -- id: unsupported_type_nested_in_protocol_extension - msg: "type %0 cannot be nested in protocol extension of %1" - -- id: unsupported_nested_protocol - msg: "protocol %0 cannot be nested inside another declaration" - -- id: where_nongeneric_ctx - msg: "'where' clause on non-generic member declaration requires a generic context" - -- id: where_nongeneric_toplevel - msg: "'where' clause cannot be applied to a non-generic top-level declaration" - -- id: type_alias_underlying_type_access - msg: "type alias %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}3|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its underlying type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - -- id: type_alias_underlying_type_access_warn - msg: "type alias %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its underlying type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - -- id: type_alias_underlying_type_not_usable_from_inline - msg: "type referenced from the underlying type of a '@usableFromInline' type alias must be '@usableFromInline' or public" - -- id: type_alias_underlying_type_not_usable_from_inline_warn - msg: "type referenced from the underlying type of a '@usableFromInline' type alias should be '@usableFromInline' or public" - -- id: subscript_type_access - msg: "subscript %select{must be declared %select{private|fileprivate|internal|%error|%error}1|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{index|element type}3 uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - -- id: subscript_type_access_warn - msg: "subscript %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{index|element type}3 uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - -- id: subscript_type_usable_from_inline - msg: "%select{index type|element type}0 of a '@usableFromInline' subscript must be '@usableFromInline' or public" - -- id: subscript_type_usable_from_inline_warn - msg: "%select{index type|element type}0 of a '@usableFromInline' subscript should be '@usableFromInline' or public" - -- id: function_type_access - msg: "%select{function|method|initializer}4 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}2|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{parameter|result}5 uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type" - -- id: function_type_spi - msg: "%select{function|method|initializer}0 cannot be declared '@_spi' because its %select{parameter|result}1 uses %select{a private|a fileprivate|an internal|a public|an open}2 type%select{| that is not '@_spi'}3" - -- id: function_type_access_warn - msg: "%select{function|method|initializer}4 %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its %select{parameter|result}5 uses %select{a private|a fileprivate|an internal|%error|%error}3 type" - -- id: function_type_usable_from_inline - msg: "the %select{parameter|result}1 of a '@usableFromInline' %select{function|method|initializer}0 must be '@usableFromInline' or public" - -- id: function_type_usable_from_inline_warn - msg: "the %select{parameter|result}1 of a '@usableFromInline' %select{function|method|initializer}0 should be '@usableFromInline' or public" - -- id: spi_attribute_on_non_public - msg: "%select{private|fileprivate|internal|%error|%error}0 %1 cannot be declared '@_spi' because only public and open declarations can be '@_spi'" - -- id: spi_attribute_on_protocol_requirement - msg: "protocol requirement %0 cannot be declared '@_spi' without a default implementation in a protocol extension" - -- id: spi_attribute_on_frozen_stored_properties - msg: "stored property %0 cannot be declared '@_spi' in a '@frozen' struct" - -- id: opaque_type_invalid_constraint - msg: "an 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or a base class" - -- id: inferred_opaque_type - msg: "property definition has inferred type %0, involving the 'some' return type of another declaration" - -- id: non_nominal_extension - msg: "non-nominal type %0 cannot be extended" - -- id: composition_in_extended_type - msg: "extending a protocol composition is not supported; extending %0 instead" - -- id: composition_in_extended_type_alternative - msg: "did you mean to extend the most specific type %0 instead?" - -- id: extension_access_with_conformances - msg: "%0 modifier cannot be used with extensions that declare protocol conformances" - -- id: extension_metatype - msg: "cannot extend a metatype %0" - -- id: extension_specialization - msg: "constrained extension must be declared on the unspecialized generic type %0 with constraints specified by a 'where' clause" - -- id: extension_stored_property - msg: "extensions must not contain stored properties" - -- id: extension_stored_property_fixit - msg: "Remove '=' to make %0 a computed property" - -- id: extension_nongeneric_trailing_where - msg: "trailing 'where' clause for extension of non-generic type %0" - -- id: extension_protocol_inheritance - msg: "extension of protocol %0 cannot have an inheritance clause" - -- id: objc_generic_extension_using_type_parameter - msg: "extension of a generic Objective-C class cannot access the class's generic parameters at runtime" - -- id: objc_generic_extension_using_type_parameter_here - msg: "generic parameter used here" - -- id: objc_generic_extension_using_type_parameter_try_objc - msg: "add '@objc' to allow uses of 'self' within the function body" - -- id: invalid_nominal_extension - msg: "extension of type %0 must be declared as an extension of %1" - -- id: invalid_nominal_extension_rewrite - msg: "did you mean to extend %0 instead?" - -- id: type_does_not_conform - msg: "type %0 does not conform to protocol %1" - -- id: cannot_use_nil_with_this_type - msg: "'nil' cannot be used in context expecting type %0" - -- id: type_cannot_conform_to_nsobject - msg: "cannot declare conformance to 'NSObjectProtocol' in Swift; %0 should inherit 'NSObject' instead" - -- id: use_of_equal_instead_of_equality - msg: "use of '=' in a boolean context, did you mean '=='?" - -- id: type_cannot_conform - msg: "%select{type %1|protocol %1 as a type}0 cannot conform to %select{%3|the protocol itself}2; only concrete types such as structs, enums and classes can conform to protocols" - -- id: required_by_opaque_return - msg: "required by opaque return type of %0 %1" - -- id: required_by_decl - msg: "required by %0 %1 where %2 = %3" - -- id: required_by_decl_ref - msg: "required by referencing %0 %1 on %2 where %3 = %4" - -- id: protocol_does_not_conform_static - msg: "%0 cannot be used as a type conforming to protocol %1 because %1 has static requirements" - -- id: protocol_derivation_is_broken - msg: "protocol %0 is broken; cannot derive conformance for type %1" - -- id: type_does_not_inherit - msg: "%0 requires that %1 inherit from %2" - -- id: type_does_not_inherit_or_conform_requirement - msg: "requirement specified as %0 : %1%2" - -- id: types_not_equal - msg: "%0 requires the types %1 and %2 be equivalent" - -- id: type_does_not_conform_owner - msg: "%0 requires that %1 conform to %2" - -- id: type_does_not_conform_in_decl_ref - msg: "referencing %0 %1 on %2 requires that %3 conform to %4" - -- id: type_does_not_conform_anyobject_in_decl_ref - msg: "referencing %0 %1 on %2 requires that %3 be a class type" - -- id: type_does_not_conform_decl_owner - msg: "%0 %1 requires that %2 conform to %3" - -- id: type_does_not_conform_anyobject_decl_owner - msg: "%0 %1 requires that %2 be a class type" - -- id: type_does_not_conform_in_opaque_return - msg: "return type of %0 %1 requires that %2 %select{conform to %3|be a class type}4" - -- id: types_not_equal_decl - msg: "%0 %1 requires the types %2 and %3 be equivalent" - -- id: types_not_equal_in_decl_ref - msg: "referencing %0 %1 on %2 requires the types %3 and %4 be equivalent" - -- id: types_not_inherited_decl - msg: "%0 %1 requires that %2 inherit from %3" - -- id: types_not_inherited_in_decl_ref - msg: "referencing %0 %1 on %2 requires that %3 inherit from %4" - -- id: where_requirement_failure_one_subst - msg: "where %0 = %1" - -- id: where_requirement_failure_both_subst - msg: "where %0 = %1, %2 = %3" - -- id: requirement_implied_by_conditional_conformance - msg: "requirement from conditional conformance of %0 to %1" - -- id: wrapped_type_satisfies_requirement - msg: "wrapped type %0 satisfies this requirement; did you mean to unwrap?" - -- id: candidate_types_conformance_requirement - msg: "candidate requires that %0 conform to %1 (requirement specified as %2 == %3%4)" - -- id: candidate_types_equal_requirement - msg: "candidate requires that the types %0 and %1 be equivalent (requirement specified as %2 == %3%4)" - -- id: candidate_types_inheritance_requirement - msg: "candidate requires that %1 inherit from %2 (requirement specified as %2 : %3%4)" - -- id: types_not_equal_requirement - msg: "requirement specified as %0 == %1%2" - -- id: type_is_not_a_class - msg: "%0 requires that %1 be a class type" - -- id: anyobject_requirement - msg: "requirement specified as %0 : 'AnyObject'%2" - -- id: non_class_cannot_conform_to_class_protocol - msg: "non-class type %0 cannot conform to class protocol %1" - -- id: cf_class_cannot_conform_to_objc_protocol - msg: "Core Foundation class %0 cannot conform to @objc protocol %1 because Core Foundation types are not classes in Objective-C" - -- id: objc_runtime_visible_cannot_conform_to_objc_protocol - msg: "class %0 cannot conform to @objc protocol %1 because the class is only visible via the Objective-C runtime" - -- id: objc_generics_cannot_conditionally_conform - msg: "type %0 cannot conditionally conform to protocol %1 because the type uses the Objective-C generics model" - -- id: objc_protocol_cannot_have_conditional_conformance - msg: "type %0 cannot conditionally conform to @objc protocol %1 because Objective-C does not support conditional conformances" - -- id: objc_protocol_in_generic_extension - msg: "conformance of %select{class from generic context|generic class}0 %1 to @objc protocol %2 cannot be in an extension" - -- id: conditional_conformances_cannot_imply_conformances - msg: "conditional conformance of type %0 to protocol %1 does not imply conformance to inherited protocol %2" - -- id: note_explicitly_state_conditional_conformance_different - msg: "did you mean to explicitly state the conformance with different bounds?" - -- id: note_explicitly_state_conditional_conformance_relaxed - msg: "did you mean to explicitly state the conformance with relaxed bounds?" - -- id: note_explicitly_state_conditional_conformance_same - msg: "did you mean to explicitly state the conformance with the same bounds?" - -- id: note_explicitly_state_conditional_conformance_noneditor - msg: "did you mean to explicitly state the conformance like '%0where ...'?" - -- id: protocol_has_missing_requirements - msg: "type %0 cannot conform to protocol %1 because it has requirements that cannot be satisfied" - -- id: protocol_has_missing_requirements_versioned - msg: "type %0 cannot conform to protocol %1 (compiled with Swift %2) because it has requirements that could not be loaded in Swift %3" - -- id: requirement_restricts_self - msg: "%0 requirement %1 cannot add constraint '%2%select{:|:| ==|:}3 %4' on 'Self'" - -- id: witness_argument_name_mismatch - msg: "%0 %1 has different argument labels from those required by protocol %2 (%3)" - -- id: witness_initializer_not_required - msg: "initializer requirement %0 can only be satisfied by a 'required' initializer in%select{| the definition of}1 non-final class %2" - -- id: witness_initializer_failability - msg: "non-failable initializer requirement %0%select{| in Objective-C protocol}1 cannot be satisfied by a failable initializer ('init%select{?|!}1')" - -- id: witness_self_non_subtype - msg: "protocol %0 requirement %1 cannot be satisfied by a non-final class (%2) because it uses 'Self' in a non-parameter, non-result type position" - -- id: witness_self_same_type - msg: "%0 %1 in non-final class %2 cannot be used to satisfy requirement %3 %4 (in protocol %5) due to same-type requirement involving 'Self'" - -- id: witness_self_weaken_same_type - msg: "consider weakening the same-type requirement %0 == %1 to a superclass requirement" - -- id: witness_requires_dynamic_self - msg: "method %0 in non-final class %1 must return 'Self' to conform to protocol %2" - -- id: witness_requires_class_implementation - msg: "method %0 in non-final class %1 cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements" - -- id: witness_not_accessible_proto - msg: "%select{initializer %1|method %1|%select{|setter for }2property %1|subscript%select{| setter}2}0 must be declared %select{%error|fileprivate|internal|public|%error}3 because it matches a requirement in %select{private|fileprivate|internal|public|%error}4 protocol %5" - -- id: witness_not_accessible_type - msg: "%select{initializer %1|method %1|%select{|setter for }2property %1|subscript%select{| setter}2}0 must be as accessible as its enclosing type because it matches a requirement in protocol %5" - -- id: type_witness_not_accessible_proto - msg: "%0 %1 must be declared %select{%error|fileprivate|internal|public|%error}2 because it matches a requirement in %select{%error|fileprivate|internal|public|%error}2 protocol %3" - -- id: type_witness_not_accessible_type - msg: "%0 %1 must be as accessible as its enclosing type because it matches a requirement in protocol %3" - -- id: witness_not_usable_from_inline - msg: "%0 %1 must be declared '@usableFromInline' because it matches a requirement in protocol %2" - -- id: witness_not_usable_from_inline_warn - msg: "%0 %1 should be declared '@usableFromInline' because it matches a requirement in protocol %2" - -- id: type_witness_objc_generic_parameter - msg: "type %0 involving Objective-C type parameter%select{| %1}2 cannot be used for associated type %3 of protocol %4" - -- id: witness_fix_access - msg: "mark the %0 as '%select{%error|fileprivate|internal|public|%error}1' to satisfy the requirement" - -- id: witness_move_to_another_extension - msg: "move the %0 to another extension where it can be declared '%select{%error|%error|internal|public|%error}1' to satisfy the requirement" - -- id: assoc_type_default_conformance_failed - msg: "default type %0 for associated type %1 does not satisfy constraint %2: %3" - -- id: assoc_type_default_here - msg: "associated type %0 has default type %1 written here" - -- id: protocol_access - msg: "%select{protocol must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}4 because %select{it refines|its 'where' clause uses}2|%select{in this context|fileprivate|internal|public|%error}1 %select{protocol cannot refine|protocol's 'where' clause cannot use}2}0 %select{a private|a fileprivate|an internal|%error|%error}3 %5" - -- id: protocol_access_warn - msg: "%select{protocol should be declared %select{private|fileprivate|internal|%error|%error}1 because %select{it refines|its 'where' clause uses}2|%select{in this context|fileprivate|internal|public|%error}1 %select{protocol should not refine|protocol's 'where' clause should not use}2}0 %select{a private|a fileprivate|an internal|%error|%error}3 %5" - -- id: protocol_usable_from_inline - msg: "protocol %select{refined|used}0 by '@usableFromInline' protocol must be '@usableForInline' or public" - -- id: protocol_usable_from_inline_warn - msg: "protocol %select{refined|used}0 by '@usableFromInline' protocol should be '@usableForInline' or public" - -- id: protocol_property_must_be_computed_var - msg: "protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier" - -- id: protocol_property_must_be_computed - msg: "property in protocol must have explicit { get } or { get set } specifier" - -- id: inherited_protocol_does_not_conform - msg: "type %0 does not conform to inherited protocol %1" - -- id: no_witnesses - msg: "protocol requires %select{initializer %1|function %1|property %1|subscript}0 with type %2%select{|; do you want to add a stub?}3" - -- id: missing_witnesses_general - msg: "do you want to add protocol stubs?" - -- id: ambiguous_witnesses - msg: "multiple matching %select{initializers named %1|functions named %1|properties named %1|subscript operators}0 with type %2" - -- id: ambiguous_witnesses_wrong_name - msg: "multiple matching %select{initializers named %1|functions named %1|properties named %1|subscript operators}0 with type %2" - -- id: no_witnesses_type - msg: "protocol requires nested type %0; do you want to add it?" - -- id: default_associated_type_req_fail - msg: "default type %0 for associated type %1 (from protocol %2) does not %select{inherit from|conform to}4 %3" - -- id: associated_type_access - msg: "associated type in %select{a private|a fileprivate|an internal|a public|%error}0 protocol uses %select{a private|a fileprivate|an internal|%error|%error}1 type in its %select{default definition|requirement}2 " - -- id: associated_type_access_warn - msg: "associated type in %select{a private|a fileprivate|an internal|a public|%error}0 protocol uses %select{a private|a fileprivate|an internal|%error|%error}1 type in its %select{default definition|requirement}2 " - -- id: associated_type_not_usable_from_inline - msg: "type referenced from a %select{default definition|requirement}0 of an associated type in a '@usableFromInline' protocol must be '@usableFromInline' or public" - -- id: associated_type_not_usable_from_inline_warn - msg: "type referenced from a %select{default definition|requirement}0 of an associated type in a '@usableFromInline' protocol should be '@usableFromInline' or public" - -- id: bad_associated_type_deduction - msg: "unable to infer associated type %0 for protocol %1" - -- id: associated_type_deduction_witness_failed - msg: "candidate would match and infer %0 = %1 if %1 %select{inherited from|conformed to}3 %2" - -- id: associated_type_witness_conform_impossible - msg: "candidate can not infer %0 = %1 because %1 is not a nominal type and so can't conform to %2" - -- id: associated_type_witness_inherit_impossible - msg: "candidate can not infer %0 = %1 because %1 is not a class type and so can't inherit from %2" - -- id: ambiguous_associated_type_deduction - msg: "ambiguous inference of associated type %0: %1 vs. %2" - -- id: associated_type_deduction_witness - msg: "matching requirement %0 to this declaration inferred associated type to %1" - -- id: associated_type_deduction_default - msg: "using associated type default %0" - -- id: ambiguous_witnesses_type - msg: "multiple matching types named %0" - -- id: protocol_witness_exact_match - msg: "candidate exactly matches%0" - -- id: protocol_witness_renamed - msg: "rename to %0 to satisfy this requirement%1" - -- id: protocol_witness_kind_conflict - msg: "candidate is not %select{an initializer|a function|a variable|a subscript}0" - -- id: protocol_witness_type_conflict - msg: "candidate has non-matching type %0%1" - -- id: protocol_witness_missing_requirement - msg: "candidate would match if %0 %select{conformed to|subclassed|was the same type as}2 %1" - -- id: protocol_witness_optionality_conflict - msg: "candidate %select{type has|result type has|parameter type has|parameter types have|result and parameter types have}0 incorrect optionality%1" - -- id: err_protocol_witness_optionality - msg: "%select{type|result|parameter|parameters|result and parameters}0 of %1 %select{has|has|has|have|have|}0 different optionality than required by protocol %2" - -- id: warn_protocol_witness_optionality - msg: "%select{type|result|parameter|parameters|result and parameters}0 of %1 %select{has|has|has|have|have|}0 different optionality than expected by protocol %2" - -- id: protocol_witness_static_conflict - msg: "candidate operates on %select{a type|an instance}0, not %select{an instance|a type}0 as required" - -- id: protocol_witness_prefix_postfix_conflict - msg: "candidate is %select{|prefix, |postfix, }1not %select{prefix|postfix}0 as required" - -- id: protocol_witness_mutation_modifier_conflict - msg: "candidate is marked %0 but protocol does not allow it" - -- id: protocol_witness_settable_conflict - msg: "candidate is not settable, but protocol requires it" - -- id: protocol_witness_rethrows_conflict - msg: "candidate is not 'rethrows', but protocol requires it" - -- id: protocol_witness_throws_conflict - msg: "candidate throws, but protocol does not allow it" - -- id: protocol_witness_not_objc - msg: "candidate is explicitly '@nonobjc'" - -- id: protocol_witness_enum_case_payload - msg: "candidate is an enum case with associated values, but protocol does not allow it" - -- id: protocol_witness_type - msg: "possibly intended match" - -- id: protocol_witness_nonconform_type - msg: "possibly intended match %0 does not %select{inherit from|conform to}2 %1" - -- id: protocol_witness_circularity - msg: "candidate references itself" - -- id: protocol_conformance_here - msg: "%select{|class }0%1 declares conformance to protocol %2 here" - -- id: declared_protocol_conformance_here - msg: "%select{%0 inherits conformance to protocol %2 from superclass|%0 declares conformance to protocol %2|%0 implicitly conforms to protocol %2 (via conformance to %3)|%0 implicitly conforms to protocol %2}1 here" - -- id: witness_unavailable - msg: "unavailable %0 %1 was used to satisfy a requirement of protocol %2" - -- id: redundant_conformance - msg: "redundant conformance of %0 to protocol %1" - -- id: redundant_conformance_conditional - msg: "conflicting conformance of %0 to protocol %1; there cannot be more than one conformance, even with different conditional bounds" - -- id: redundant_conformance_adhoc - msg: "conformance of %0 to protocol %1 was already stated in %select{the protocol's|the type's}2 module %3" - -- id: redundant_conformance_adhoc_conditional - msg: "conformance of %0 to protocol %1 conflicts with that stated in %select{the protocol's|the type's}2 module %3 and will be ignored; there cannot be more than one conformance, even with different conditional bounds" - -- id: redundant_conformance_witness_ignored - msg: "%0 %1 will not be used to satisfy the conformance to %2" - -- id: req_near_match - msg: "%0 %1 nearly matches %select{defaulted|optional}2 requirement %3 of protocol %4" - -- id: optional_req_nonobjc_near_match_add_objc - msg: "add '@objc' to provide an Objective-C entrypoint" - -- id: req_near_match_move - msg: "move %0 to %select{an|another}1 extension to silence this warning" - -- id: req_near_match_nonobjc - msg: "add '@nonobjc' to silence this %select{warning|error}0" - -- id: req_near_match_access - msg: "make %0 %select{ERROR|private|private|non-public|non-public}1 to silence this warning" - -- id: missing_append_interpolation - msg: "type conforming to 'StringInterpolationProtocol' does not implement a valid 'appendInterpolation' method" - -- id: append_interpolation_static - msg: "'appendInterpolation' method will never be used because it is static" - -- id: append_interpolation_void_or_discardable - msg: "'appendInterpolation' method does not return 'Void' or have a discardable result" - -- id: append_interpolation_access_control - msg: "'appendInterpolation' method is %select{private|fileprivate|internal|public|open}0, but %1 is %select{private|fileprivate|internal|public|open}2" - -- id: assoc_type_outside_of_protocol - msg: "associated type %0 can only be used with a concrete type or generic parameter base" - -- id: typealias_outside_of_protocol - msg: "type alias %0 can only be used with a concrete type or generic parameter base" - -- id: objc_protocol_inherits_non_objc_protocol - msg: "@objc protocol %0 cannot refine non-@objc protocol %1" - -- id: protocol_where_clause_self_requirement - msg: "constraint with subject type of 'Self' is not supported; consider adding requirement to protocol inheritance clause instead" - -- id: invalid_protocol_composition_member - msg: "non-protocol, non-class type %0 cannot be used within a protocol-constrained type" - -- id: protocol_composition_one_class - msg: "protocol-constrained type cannot contain class %0 because it already contains class %1" - -- id: requires_conformance_nonprotocol - msg: "type %0 constrained to non-protocol, non-class type %1" - -- id: requires_conformance_nonprotocol_fixit - msg: "use '%0 == %1' to require '%0' to be '%1'" - -- id: requires_not_suitable_archetype - msg: "type %0 in conformance requirement does not refer to a generic parameter or associated type" - -- id: requires_no_same_type_archetype - msg: "neither type in same-type constraint (%0 or %1) refers to a generic parameter or associated type" - -- id: requires_generic_params_made_equal - msg: "same-type requirement makes generic parameters %0 and %1 equivalent" - -- id: requires_generic_param_made_equal_to_concrete - msg: "same-type requirement makes generic parameter %0 non-generic" - -- id: recursive_decl_reference - msg: "%0 %1 references itself" - -- id: recursive_same_type_constraint - msg: "same-type constraint %0 == %1 is recursive" - -- id: recursive_superclass_constraint - msg: "superclass constraint %0 : %1 is recursive" - -- id: requires_generic_param_same_type_does_not_conform - msg: "same-type constraint type %0 does not conform to required protocol %1" - -- id: requires_same_concrete_type - msg: "generic signature requires types %0 and %1 to be the same" - -- id: redundant_conformance_constraint - msg: "redundant conformance constraint %0: %1" - -- id: redundant_conformance_here - msg: "conformance constraint %1: %2 %select{written here|implied here|inferred from type here}0" - -- id: unsupported_recursive_requirements - msg: "requirement involves recursion that is not currently supported" - -- id: same_type_conflict - msg: "%select{generic parameter |protocol |}0%1 cannot be equal to both %2 and %3" - -- id: redundant_same_type_to_concrete - msg: "redundant same-type constraint %0 == %1" - -- id: same_type_redundancy_here - msg: "same-type constraint %1 == %2 %select{written here|implied here|inferred from type here}0" - -- id: requires_superclass_conflict - msg: "%select{generic parameter %1 cannot|protocol %1 cannot require 'Self' to|%1 cannot}0 be a subclass of both %2 and %3" - -- id: redundant_superclass_constraint - msg: "redundant superclass constraint %0 : %1" - -- id: superclass_redundancy_here - msg: "superclass constraint %1 : %2 %select{written here|implied here|inferred from type here}0" - -- id: conflicting_layout_constraints - msg: "%select{generic parameter |protocol |}0%1 has conflicting constraints %2 and %3" - -- id: redundant_layout_constraint - msg: "redundant constraint %0 : %1" - -- id: previous_layout_constraint - msg: "constraint %1 : %2 %select{written here|implied here|inferred from type here}0" - -- id: redundant_same_type_constraint - msg: "redundant same-type constraint %0 == %1" - -- id: previous_same_type_constraint - msg: "previous same-type constraint %1 == %2 %select{written here|implied here|inferred from type here}0" - -- id: inherited_associated_type_redecl - msg: "redeclaration of associated type %0 from protocol %1 is better expressed as a 'where' clause on the protocol" - -- id: typealias_override_associated_type - msg: "typealias overriding associated type %0 from protocol %1 is better expressed as same-type constraint on the protocol" - -- id: associated_type_override_typealias - msg: "associated type %0 is redundant with type %0 declared in inherited %1 %2" - -- id: associated_type_objc - msg: "associated type %0 cannot be declared inside '@objc' protocol %1" - -- id: generic_param_access - msg: "%0 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}2}1 because its generic %select{parameter|requirement}5 uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type" - -- id: generic_param_access_warn - msg: "%0 %select{should be declared %select{private|fileprivate|internal|%error|%error}3|should not be declared %select{in this context|fileprivate|internal|public|open}2}1 because its generic %select{parameter|requirement}5 uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type" - -- id: generic_param_usable_from_inline - msg: "type referenced from a generic %select{parameter|requirement}1 of a '@usableFromInline' %0 must be '@usableFromInline' or public" - -- id: generic_param_usable_from_inline_warn - msg: "type referenced from a generic %select{parameter|requirement}1 of a '@usableFromInline' %0 should be '@usableFromInline' or public" - -- id: override_multiple_decls_base - msg: "declaration %0 cannot override more than one superclass declaration" - -- id: override_multiple_decls_arg_mismatch - msg: "declaration %0 has different argument labels from any potential overrides" - -- id: overridden_near_match_here - msg: "potential overridden %0 %1 here" - -- id: override_decl_extension - msg: "overriding %select{|non-@objc }0declarations %select{in extensions|from extensions}0 is not supported" - -- id: overridden_here - msg: "overridden declaration is here" - -- id: overridden_here_can_be_objc - msg: "add '@objc' to make this declaration overridable" - -- id: missing_override - msg: "overriding declaration requires an 'override' keyword" - -- id: missing_override_warn - msg: "implicit override should be marked with 'override' or suppressed with '@_nonoverride'" - -- id: multiple_override - msg: "%0 has already been overridden" - -- id: multiple_override_prev - msg: "%0 previously overridden here" - -- id: override_unavailable - msg: "cannot override %0 which has been marked unavailable%select{|: %1}1" - -- id: suggest_removing_override - msg: "remove 'override' modifier to declare a new %0" - -- id: override_less_available - msg: "overriding %0 must be as available as declaration it overrides" - -- id: override_accessor_less_available - msg: "overriding %0 for %1 must be as available as declaration it overrides" - -- id: override_let_property - msg: "cannot override immutable 'let' property %0 with the getter of a 'var'" - -- id: override_not_accessible - msg: "%select{|setter of }0overriding %1 must be as accessible as %select{its enclosing type|the declaration it overrides}2" - -- id: override_of_non_open - msg: "overriding non-open %0 outside of its defining module" - -- id: method_does_not_override - msg: "method does not override any method from its %select{parent protocol|superclass}0" - -- id: property_does_not_override - msg: "property does not override any property from its %select{parent protocol|superclass}0" - -- id: subscript_does_not_override - msg: "subscript does not override any subscript from its %select{parent protocol|superclass}0" - -- id: initializer_does_not_override - msg: "initializer does not override a designated initializer from its %select{parent protocol|superclass}0" - -- id: failable_initializer_override - msg: "failable initializer %0 cannot override a non-failable initializer" - -- id: nonfailable_initializer_override_here - msg: "non-failable initializer %0 overridden here" - -- id: property_override_here - msg: "attempt to override property here" - -- id: subscript_override_here - msg: "attempt to override subscript here" - -- id: convenience_init_override_here - msg: "attempt to override convenience initializer here" - -- id: override_type_mismatch_with_fixits - msg: "type does not match superclass %0 with type %1" - -- id: override_type_mismatch_with_fixits_init - msg: "type does not match superclass initializer with %select{no arguments|argument %1|arguments %1}0" - -- id: override_nonclass_decl - msg: "'override' can only be specified on class members" - -- id: nonoverride_wrong_decl_context - msg: "'@_nonoverride' can only be specified on class or protocol members" - -- id: nonoverride_and_override_attr - msg: "'override' cannot be combined with '@_nonoverride'" - -- id: override_property_type_mismatch - msg: "property %0 with type %1 cannot override a property with type %2" - -- id: override_with_stored_property - msg: "cannot override with a stored property %0" - -- id: override_with_stored_property_warn - msg: "cannot override with a stored property %0" - -- id: observing_readonly_property - msg: "cannot observe read-only property %0; it can't change" - -- id: override_mutable_with_readonly_property - msg: "cannot override mutable property with read-only property %0" - -- id: override_argument_name_mismatch - msg: "argument labels for %select{method|initializer}0 %1 do not match those of overridden %select{method|initializer}0 %2" - -- id: override_ownership_mismatch - msg: "cannot override %0 property with %1 property" - -- id: override_dynamic_self_mismatch - msg: "cannot override a Self return type with a non-Self return type" - -- id: override_class_declaration_in_extension - msg: "cannot override a non-dynamic class declaration from an extension" - -- id: override_throws - msg: "cannot override non-throwing %select{method|initializer}0 with throwing %select{method|initializer}0" - -- id: override_throws_objc - msg: "overriding a throwing @objc %select{method|initializer}0 with a non-throwing %select{method|initializer}0 is not supported" - -- id: satisfy_throws_objc - msg: "satisfying a throwing @objc %select{method|initializer}0 with a non-throwing %select{method|initializer}0 is not supported" - -- id: override_optional_mismatch - msg: "cannot override %0 %select{parameter|index}1 of type %2 with non-optional type %3" - -- id: override_optional_result_mismatch - msg: "cannot override %0 %select{result|element}1 type %2 with optional type %3" - -- id: override_unnecessary_IUO - msg: "overriding %0 parameter of type %1 with implicitly unwrapped optional type %2" - -- id: override_unnecessary_result_IUO - msg: "overriding %0 optional result type %1 with implicitly unwrapped optional type %2" - -- id: override_unnecessary_IUO_remove - msg: "remove '!' to make the parameter required" - -- id: override_unnecessary_IUO_use_strict - msg: "use '?' to make the result optional" - -- id: override_unnecessary_IUO_silence - msg: "add parentheses to silence this warning" - -- id: override_mutable_covariant_property - msg: "cannot override mutable property %0 of type %1 with covariant type %2" - -- id: override_mutable_covariant_subscript - msg: "cannot override mutable subscript of type %0 with covariant type %1" - -- id: static_decl_already_final - msg: "static declarations are already final" - -- id: open_decl_cannot_be_final - msg: "%0 cannot be declared both 'final' and 'open'" - -- id: implicitly_final_cannot_be_open - msg: "%select{'let' properties|members of 'final' classes|static declarations}0 are implicitly 'final'; use 'public' instead of 'open'" - -- id: implicitly_final_cannot_be_open_swift4 - msg: "%select{'let' properties|members of 'final' classes|static declarations}0 are implicitly 'final'; use 'public' instead of 'open'" - -- id: override_swift3_objc_inference - msg: "override of %0 %1 from extension of %2 depends on deprecated inference of '@objc'" - -- id: override_method_different_generic_sig - msg: "overridden method %0 has generic signature %1 which is incompatible with base method's generic signature %2; expected generic signature to be %3" - -- id: duplicate_inheritance - msg: "duplicate inheritance from %0" - -- id: duplicate_anyobject_class_inheritance - msg: "redundant inheritance from 'AnyObject' and Swift 3 'class' keyword" - -- id: inheritance_from_protocol_with_superclass - msg: "inheritance from class-constrained protocol composition type %0" - -- id: multiple_inheritance - msg: "multiple inheritance from classes %0 and %1" - -- id: inheritance_from_non_protocol_or_class - msg: "inheritance from non-protocol, non-class type %0" - -- id: inheritance_from_non_protocol - msg: "inheritance from non-protocol type %0" - -- id: superclass_not_first - msg: "superclass %0 must appear first in the inheritance clause" - -- id: superclass_not_open - msg: "cannot inherit from non-open class %0 outside of its defining module" - -- id: superclass_here - msg: "superclass is declared here" - -- id: superclass_of_open_not_open - msg: "superclass %0 of open class must be open" - -- id: inheritance_from_final_class - msg: "inheritance from a final class %0" - -- id: inheritance_from_unspecialized_objc_generic_class - msg: "inheritance from a generic Objective-C class %0 must bind type parameters of %0 to specific concrete types" - -- id: inheritance_from_class_with_missing_vtable_entries - msg: "cannot inherit from class %0 because it has overridable members that could not be loaded" - -- id: inheritance_from_class_with_missing_vtable_entries_versioned - msg: "cannot inherit from class %0 (compiled with Swift %1) because it has overridable members that could not be loaded in Swift %2" - -- id: inheritance_from_cf_class - msg: "cannot inherit from Core Foundation type %0" - -- id: inheritance_from_objc_runtime_visible_class - msg: "cannot inherit from class %0 because it is only visible via the Objective-C runtime" - -- id: enum_case_access - msg: "enum case in %select{a private|a fileprivate|an internal|a public|%error}0 enum uses %select{a private|a fileprivate|an internal|%error|%error}1 type" - -- id: enum_case_access_warn - msg: "enum case in %select{a private|a fileprivate|an internal|a public|%error}0 enum uses %select{a private|a fileprivate|an internal|%error|%error}1 type" - -- id: enum_case_usable_from_inline - msg: "type of enum case in '@usableFromInline' enum must be '@usableFromInline' or public" - -- id: enum_case_usable_from_inline_warn - msg: "type of enum case in '@usableFromInline' enum should be '@usableFromInline' or public" - -- id: enum_stored_property - msg: "enums must not contain stored properties" - -- id: multiple_enum_raw_types - msg: "multiple enum raw types %0 and %1" - -- id: raw_type_not_first - msg: "raw type %0 must appear first in the enum inheritance clause" - -- id: raw_type_not_literal_convertible - msg: "raw type %0 is not expressible by a string, integer, or floating-point literal" - -- id: enum_raw_type_not_equatable - msg: "RawRepresentable conformance cannot be synthesized because raw type %0 is not Equatable" - -- id: enum_raw_type_nonconforming_and_nonsynthable - msg: "%0 declares raw type %1, but does not conform to RawRepresentable and conformance could not be synthesized" - -- id: enum_declares_rawrep_with_raw_type - msg: "%0 declares raw type %1, which implies RawRepresentable" - -- id: enum_raw_type_access - msg: "enum %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}3|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its raw type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - -- id: enum_raw_type_access_warn - msg: "enum %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its raw type uses %select{a private|a fileprivate|an internal|%error|%error}2 type" - -- id: enum_raw_type_not_usable_from_inline - msg: "type referenced from the raw type of a '@usableFromInline' enum must be '@usableFromInline' or public" - -- id: enum_raw_type_not_usable_from_inline_warn - msg: "type referenced from the raw type of a '@usableFromInline' enum should be '@usableFromInline' or public" - -- id: empty_enum_raw_type - msg: "an enum with no cases cannot declare a raw type" - -- id: enum_raw_value_without_raw_type - msg: "enum case cannot have a raw value if the enum does not have a raw type" - -- id: enum_with_raw_type_case_with_argument - msg: "enum with raw type cannot have cases with arguments" - -- id: enum_raw_type_here - msg: "declared raw type %0 here" - -- id: objc_enum_no_raw_type - msg: "'@objc' enum must declare an integer raw type" - -- id: objc_enum_raw_type_not_integer - msg: "'@objc' enum raw type %0 is not an integer type" - -- id: enum_non_integer_raw_value_auto_increment - msg: "enum case must declare a raw value when the preceding raw value is not an integer" - -- id: enum_non_integer_convertible_raw_type_no_value - msg: "enum cases require explicit raw values when the raw type is not expressible by integer or string literal" - -- id: enum_raw_value_not_unique - msg: "raw value for enum case is not unique" - -- id: enum_raw_value_magic_literal - msg: "use of '%0' literal as raw value for enum case is not supported" - -- id: enum_raw_value_used_here - msg: "raw value previously used here" - -- id: enum_raw_value_incrementing_from_here - msg: "raw value auto-incremented from here" - -- id: enum_raw_value_incrementing_from_zero - msg: "raw value implicitly auto-incremented from zero" - -- id: construct_raw_representable_from_unwrapped_value - msg: "construct %0 from unwrapped %1 value" - -- id: decl_from_hidden_module - msg: "cannot use %0 %1 %select{here|as property wrapper here|in an extension with public or '@usableFromInline' members|in an extension with conditional conformances}2; %select{%3 has been imported as implementation-only|it is an SPI imported from %3|it is SPI}4" - -- id: decl_from_hidden_module_warn - msg: "cannot use %0 %1 %select{in SPI|as property wrapper in SPI|in an extension with public or '@usableFromInline' members|in an extension with conditional conformances}2; %select{%3 has been imported as implementation-only}4" - -- id: conformance_from_implementation_only_module - msg: "cannot use conformance of %0 to %1 %select{here|as property wrapper here|in an extension with public or '@usableFromInline' members|in an extension with conditional conformances}2; %3 has been imported as implementation-only" - -- id: assoc_conformance_from_implementation_only_module - msg: "cannot use conformance of %0 to %1 in associated type %3 (inferred as %4); %2 has been imported as implementation-only" - -- id: unexportable_clang_function_type - msg: "cannot export the underlying C type of the function type %0; it may use anonymous types or types defined outside of a module" - -- id: warn_implementation_only_conflict - msg: "%0 inconsistently imported as implementation-only" - -- id: implementation_only_conflict_here - msg: "imported as implementation-only here" - -- id: implementation_only_decl_non_override - msg: "'@_implementationOnly' can only be used on overrides" - -- id: implementation_only_override_changed_type - msg: "'@_implementationOnly' override must have the same type as the declaration it overrides (%0)" - -- id: implementation_only_override_without_attr - msg: "override of '@_implementationOnly' %0 should also be declared '@_implementationOnly'" - -- id: implementation_only_override_import_without_attr - msg: "override of %0 imported as implementation-only must be declared '@_implementationOnly'" - -- id: cannot_synthesize_init_in_extension_of_nonfinal - msg: "implementation of %0 for non-final class cannot be automatically synthesized in extension because initializer requirement %1 can only be satisfied by a 'required' initializer in the class definition" - -- id: cannot_synthesize_in_crossfile_extension - msg: "extension outside of file declaring %0 %1 prevents automatic synthesis of %2 for protocol %3" - -- id: broken_additive_arithmetic_requirement - msg: "AdditiveArithmetic protocol is broken: unexpected requirement" - -- id: broken_case_iterable_requirement - msg: "CaseIterable protocol is broken: unexpected requirement" - -- id: broken_raw_representable_requirement - msg: "RawRepresentable protocol is broken: unexpected requirement" - -- id: broken_comparable_requirement - msg: "Comparable protocol is broken: unexpected requirement" - -- id: broken_equatable_requirement - msg: "Equatable protocol is broken: unexpected requirement" - -- id: broken_hashable_requirement - msg: "Hashable protocol is broken: unexpected requirement" - -- id: broken_hashable_no_hasher - msg: "Hashable protocol is broken: Hasher type not found" - -- id: broken_errortype_requirement - msg: "Error protocol is broken: unexpected requirement" - -- id: broken_int_hashable_conformance - msg: "Int type is broken: does not conform to Hashable" - -- id: broken_int_integer_literal_convertible_conformance - msg: "Int type is broken: does not conform to ExpressibleByIntegerLiteral" - -- id: no_less_than_overload_for_int - msg: "no overload of '<' for Int" - -- id: no_equal_overload_for_int - msg: "no overload of '==' for Int" - -- id: broken_coding_key_requirement - msg: "CodingKey protocol is broken: unexpected requirement" - -- id: broken_encodable_requirement - msg: "Encodable protocol is broken: unexpected requirement" - -- id: broken_decodable_requirement - msg: "Decodable protocol is broken: unexpected requirement" - -- id: broken_differentiable_requirement - msg: "Differentiable protocol is broken: unexpected requirement" - -- id: differentiable_nondiff_type_implicit_noderivative_fixit - msg: "stored property %0 has no derivative because %1 does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute%select{|, or conform %2 to 'AdditiveArithmetic'}3" - -- id: differentiable_immutable_wrapper_implicit_noderivative_fixit - msg: "synthesis of the 'Differentiable.move(along:)' requirement for %1 requires 'wrappedValue' in property wrapper %0 to be mutable; add an explicit '@noDerivative' attribute%select{|, or conform %1 to 'AdditiveArithmetic'}2" - -- id: differentiable_let_property_implicit_noderivative_fixit - msg: "synthesis of the 'Differentiable.move(along:)' requirement for %0 requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute%select{|, or conform %0 to 'AdditiveArithmetic'}1" - -- id: codable_extraneous_codingkey_case_here - msg: "CodingKey case %0 does not match any stored properties" - -- id: codable_non_conforming_property_here - msg: "cannot automatically synthesize %0 because %1 does not conform to %0" - -- id: codable_non_decoded_property_here - msg: "cannot automatically synthesize %0 because %1 does not have a matching CodingKey and does not have a default value" - -- id: codable_codingkeys_type_is_not_an_enum_here - msg: "cannot automatically synthesize %0 because 'CodingKeys' is not an enum" - -- id: codable_codingkeys_type_does_not_conform_here - msg: "cannot automatically synthesize %0 because 'CodingKeys' does not conform to CodingKey" - -- id: decodable_no_super_init_here - msg: "cannot automatically synthesize %0 because superclass does not have a callable %1" - -- id: decodable_super_init_not_designated_here - msg: "cannot automatically synthesize %0 because implementation would need to call %1, which is not designated" - -- id: decodable_inaccessible_super_init_here - msg: "cannot automatically synthesize %0 because implementation would need to call %1, which is inaccessible due to '%select{private|fileprivate|internal|%error|%error}2' protection level" - -- id: decodable_super_init_is_failable_here - msg: "cannot automatically synthesize %0 because implementation would need to call %1, which is failable" - -- id: decodable_suggest_overriding_init_here - msg: "did you mean to override 'init(from:)'?" - -- id: codable_suggest_overriding_init_here - msg: "did you mean to override 'init(from:)' and 'encode(to:)'?" - -- id: decodable_property_will_not_be_decoded - msg: "immutable property will not be decoded because it is declared with an initial value which cannot be overwritten" - -- id: decodable_property_init_or_codingkeys_implicit - msg: "set the initial value via the initializer or explicitly define a CodingKeys enum %select{including|without}0 a %1 case to silence this warning" - -- id: decodable_property_init_or_codingkeys_explicit - msg: "set the initial value via the initializer or remove the %0 case from the CodingKeys enum to silence this warning" - -- id: decodable_make_property_mutable - msg: "make the property mutable instead" - -- id: missing_member_type_conformance_prevents_synthesis - msg: "%select{associated value|stored property}0 type %1 does not conform to protocol %2, preventing synthesized conformance of %3 to %2" - -- id: automatic_protocol_synthesis_unsupported - msg: "automatic synthesis of '%0' is not supported for %select{classes|structs}1" - -- id: comparable_synthesis_raw_value_not_allowed - msg: "enum declares raw type %0, preventing synthesized conformance of %1 to %2" - -- id: dynamic_self_non_method - msg: "%select{global|local}0 function cannot return 'Self'" - -- id: dynamic_self_invalid - msg: "covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean '%0'?" - -- id: dynamic_self_in_mutable_property - msg: "mutable property cannot have covariant 'Self' type" - -- id: dynamic_self_in_stored_property - msg: "stored property cannot have covariant 'Self' type" - -- id: dynamic_self_in_mutable_subscript - msg: "mutable subscript cannot have covariant 'Self' type" - -- id: dynamic_self_invalid_property - msg: "covariant 'Self' can only appear at the top level of property type" - -- id: dynamic_self_invalid_subscript - msg: "covariant 'Self' can only appear at the top level of subscript element type" - -- id: dynamic_self_invalid_method - msg: "covariant 'Self' can only appear at the top level of method result type" - -- id: dynamic_self_stored_property_init - msg: "covariant 'Self' type cannot be referenced from a stored property initializer" - -- id: dynamic_self_default_arg - msg: "covariant 'Self' type cannot be referenced from a default argument expression" - -- id: attr_only_one_decl_kind - msg: "%0 may only be used on '%1' declarations" - -- id: attr_not_on_variadic_parameters - msg: "'%0' must not be used on variadic parameters" - -- id: attr_not_on_subscript_parameters - msg: "'%0' must not be used on subscript parameters" - -- id: attr_ambiguous_reference_to_decl - msg: "ambiguous reference to %0 in '@%1' attribute" - -- id: override_final - msg: "%0 overrides a 'final' %1" - -- id: override_static - msg: "cannot override %0" - -- id: member_cannot_be_final - msg: "only classes and class members may be marked with 'final'" - -- id: final_not_allowed_here - msg: "'final' may only be applied to classes, properties, methods, and subscripts" - -- id: final_not_on_accessors - msg: "'final' cannot be applied to accessors, it must be put on the %select{var|let|subscript}0" - -- id: override_rethrows_with_non_rethrows - msg: "override of 'rethrows' %select{method|initializer}0 should also be 'rethrows'" - -- id: rethrows_without_throwing_parameter - msg: "'rethrows' function must take a throwing function argument" - -- id: autoclosure_function_type - msg: "@autoclosure attribute only applies to function types" - -- id: invalid_autoclosure_and_convention_attributes - msg: "'@convention(%0)' attribute is not allowed on '@autoclosure' types" - -- id: autoclosure_function_input_nonunit - msg: "argument type of @autoclosure parameter must be '()'" - -- id: escaping_non_function_parameter - msg: "@escaping attribute may only be used in function parameter position" - -- id: escaping_optional_type_argument - msg: "closure is already escaping in optional type argument" - -- id: non_ephemeral_non_pointer_type - msg: "@_nonEphemeral attribute only applies to pointer types" - -- id: attr_NSManaged_not_instance_member - msg: "@NSManaged only allowed on an instance property or method" - -- id: attr_NSManaged_not_stored - msg: "@NSManaged not allowed on %select{computed|observing|addressed}0 properties" - -- id: attr_NSManaged_let_property - msg: "@NSManaged not allowed on a 'let' property" - -- id: attr_NSManaged_initial_value - msg: "@NSManaged property cannot have an initial value" - -- id: attr_NSManaged_NSCopying - msg: "@NSManaged property cannot also be marked @NSCopying" - -- id: attr_NSManaged_method_body - msg: "@NSManaged method cannot have a body; it must be provided at runtime" - -- id: nscopying_only_on_class_properties - msg: "@NSCopying may only be used on properties in classes" - -- id: nscopying_only_mutable - msg: "@NSCopying requires property to be mutable" - -- id: nscopying_only_stored_property - msg: "@NSCopying is only valid on stored properties" - -- id: nscopying_doesnt_conform - msg: "@NSCopying is only valid with types that conform to the NSCopying protocol" - -- id: attr_ApplicationMain_not_ApplicationDelegate - msg: "%select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 class must conform to the %select{'UIApplicationDelegate'|'NSApplicationDelegate'}0 protocol" - -- id: attr_generic_ApplicationMain_not_supported - msg: "generic %select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 %select{classes|classes|types}0 are not supported" - -- id: attr_ApplicationMain_multiple - msg: "%select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute can only apply to one %select{class|class|type}0 in a module" - -- id: attr_ApplicationMain_with_script - msg: "%select{'UIApplicationMain'|'NSApplicationMain'|'main'}0 attribute cannot be used in a module that contains top-level code" - -- id: attr_ApplicationMain_script_here - msg: "top-level code defined in this source file" - -- id: attr_MainType_without_main - msg: "%0 is annotated with @main and must provide a main static function of type () -> Void or () throws -> Void." - -- id: lazy_not_on_let - msg: "'lazy' cannot be used on a let" - -- id: lazy_not_on_computed - msg: "'lazy' must not be used on a computed property" - -- id: lazy_on_already_lazy_global - msg: "'lazy' must not be used on an already-lazy global" - -- id: lazy_not_in_protocol - msg: "'lazy' isn't allowed on a protocol requirement" - -- id: lazy_requires_initializer - msg: "lazy properties must have an initializer" - -- id: lazy_requires_single_var - msg: "'lazy' cannot destructure an initializer" - -- id: lazy_must_be_property - msg: "lazy is only valid for members of a struct or class" - -- id: lazy_not_strong - msg: "lazy properties cannot be %0" - -- id: lazy_var_storage_access - msg: "access to the underlying storage of a lazy property is not allowed" - -- id: attr_for_debugger_support_only - msg: "@LLDBDebuggerSupport may only be used when debugger support is on" - -- id: implements_attr_protocol_lacks_member - msg: "protocol %0 has no member %1" - -- id: implements_attr_non_protocol_type - msg: "non-protocol type in @_implements attribute" - -- id: implements_attr_protocol_not_conformed_to - msg: "containing type %0 does not conform to protocol %1" - -- id: differentiable_attr_no_vjp_or_jvp_when_linear - msg: "cannot specify 'vjp:' or 'jvp:' for linear functions; use '@transpose' attribute for transpose registration instead" - -- id: differentiable_attr_overload_not_found - msg: "%0 does not have expected type %1" - -- id: differentiable_attr_duplicate - msg: "duplicate '@differentiable' attribute with same parameters" - -- id: differentiable_attr_duplicate_note - msg: "other attribute declared here" - -- id: differentiable_attr_function_not_same_type_context - msg: "%0 is not defined in the current type context" - -- id: differentiable_attr_derivative_not_function - msg: "registered derivative %0 must be a 'func' declaration" - -- id: differentiable_attr_class_derivative_not_final - msg: "class member derivative must be final" - -- id: differentiable_attr_invalid_access - msg: "derivative function %0 is required to either be public or '@usableFromInline' because the original function %1 is public or '@usableFromInline'" - -- id: differentiable_attr_protocol_req_where_clause - msg: "'@differentiable' attribute on protocol requirement cannot specify 'where' clause" - -- id: differentiable_attr_class_member_dynamic_self_result_unsupported - msg: "'@differentiable' attribute cannot be declared on class members returning 'Self'" - -- id: differentiable_attr_nonfinal_class_init_unsupported - msg: "'@differentiable' attribute cannot be declared on 'init' in a non-final class; consider making %0 final" - -- id: differentiable_attr_empty_where_clause - msg: "empty 'where' clause in '@differentiable' attribute" - -- id: differentiable_attr_where_clause_for_nongeneric_original - msg: "'where' clause is valid only when original function is generic %0" - -- id: differentiable_attr_layout_req_unsupported - msg: "'@differentiable' attribute does not yet support layout requirements" - -- id: overriding_decl_missing_differentiable_attr - msg: "overriding declaration is missing attribute '%0'" - -- id: protocol_witness_missing_differentiable_attr - msg: "candidate is missing attribute '%0'" - -- id: protocol_witness_missing_differentiable_attr_nonpublic_other_file - msg: "non-public %1 %2 must have explicit '%0' attribute to satisfy requirement %3 %4 (in protocol %6) because it is declared in a different file than the conformance of %5 to %6" - -- id: derivative_attr_expected_result_tuple - msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; first element must have label 'value:' and second element must have label 'pullback:' or 'differential:'" - -- id: derivative_attr_invalid_result_tuple_value_label - msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; first element must have label 'value:'" - -- id: derivative_attr_invalid_result_tuple_func_label - msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; second element must have label 'pullback:' or 'differential:'" - -- id: derivative_attr_result_value_not_differentiable - msg: "'@derivative(of:)' attribute requires function to return a two-element tuple; first element type %0 must conform to 'Differentiable'" - -- id: derivative_attr_result_func_type_mismatch - msg: "function result's %0 type does not match %1" - -- id: derivative_attr_result_func_type_mismatch_note - msg: "%0 does not have expected type %1" - -- id: derivative_attr_result_func_original_note - msg: "%0 defined here" - -- id: derivative_attr_not_in_same_file_as_original - msg: "derivative not in the same file as the original function" - -- id: derivative_attr_original_stored_property_unsupported - msg: "cannot register derivative for stored property %0" - -- id: derivative_attr_class_member_dynamic_self_result_unsupported - msg: "cannot register derivative for class member %0 returning 'Self'" - -- id: derivative_attr_nonfinal_class_init_unsupported - msg: "cannot register derivative for 'init' in a non-final class; consider making %0 final" - -- id: derivative_attr_unsupported_accessor_kind - msg: "cannot register derivative for %0" - -- id: derivative_attr_class_setter_unsupported - msg: "cannot yet register derivative for class property or subscript setters" - -- id: derivative_attr_protocol_requirement_unsupported - msg: "cannot yet register derivative default implementation for protocol requirements" - -- id: derivative_attr_original_already_has_derivative - msg: "a derivative already exists for %0" - -- id: derivative_attr_duplicate_note - msg: "other attribute declared here" - -- id: derivative_attr_access_level_mismatch - msg: "derivative function must have same access level as original function; derivative function %2 is %select{private|fileprivate|internal|public|open}3, but original function %0 is %select{private|fileprivate|internal|public|open}1" - -- id: derivative_attr_fix_access - msg: "mark the derivative function as '%select{private|fileprivate|internal|@usableFromInline|@usableFromInline}0' to match the original function" - -- id: transpose_attr_invalid_linearity_parameter_or_result - msg: "cannot transpose with respect to original %select{result|parameter}1 '%0' that does not conform to 'Differentiable' and satisfy '%0 == %0.TangentVector'" - -- id: transpose_attr_overload_not_found - msg: "could not find function %0 with expected type %1" - -- id: transpose_attr_cannot_use_named_wrt_params - msg: "cannot use named 'wrt' parameters in '@transpose(of:)' attribute, found %0" - -- id: transpose_attr_wrt_self_must_be_static - msg: "the transpose of an instance method must be a 'static' method in the same type when 'self' is a linearity parameter" - -- id: transpose_attr_wrt_self_self_type_mismatch_note - msg: "the transpose is declared in %0 but the original function is declared in %1" - -- id: autodiff_attr_original_decl_ambiguous - msg: "referenced declaration %0 is ambiguous" - -- id: autodiff_attr_original_decl_ambiguous_candidate - msg: "candidate %0 found here" - -- id: autodiff_attr_original_decl_none_valid - msg: "referenced declaration %0 could not be resolved" - -- id: autodiff_attr_original_decl_invalid_kind - msg: "candidate %0 is not a 'func', 'init', 'subscript', or 'var' computed property declaration" - -- id: autodiff_attr_original_decl_missing_accessor - msg: "candidate %0 does not have a %1" - -- id: autodiff_attr_original_decl_type_mismatch - msg: "candidate %0 does not have %select{expected type|type equal to or less constrained than}2 %1" - -- id: autodiff_attr_original_decl_not_same_type_context - msg: "candidate %0 is not defined in the current type context" - -- id: autodiff_attr_original_void_result - msg: "cannot differentiate void function %0" - -- id: autodiff_attr_original_multiple_semantic_results - msg: "cannot differentiate functions with both an 'inout' parameter and a result" - -- id: autodiff_attr_result_not_differentiable - msg: "can only differentiate functions with results that conform to 'Differentiable', but %0 does not conform to 'Differentiable'" - -- id: autodiff_attr_opaque_result_type_unsupported - msg: "cannot differentiate functions returning opaque result types" - -- id: diff_function_no_parameters - msg: "%0 has no parameters to differentiate with respect to" - -- id: diff_params_clause_param_name_unknown - msg: "unknown parameter name %0" - -- id: diff_params_clause_self_instance_method_only - msg: "'self' parameter is only applicable to instance methods" - -- id: diff_params_clause_self_must_be_first - msg: "'self' parameter must come first in the parameter list" - -- id: diff_params_clause_params_not_original_order - msg: "parameters must be specified in original order" - -- id: diff_params_clause_param_index_out_of_range - msg: "parameter index is larger than total number of parameters" - -- id: diff_params_clause_no_inferred_parameters - msg: "no differentiation parameters could be inferred; must differentiate with respect to at least one parameter conforming to 'Differentiable'" - -- id: diff_params_clause_cannot_diff_wrt_inout_parameter - msg: "cannot differentiate with respect to 'inout' parameter (%0)" - -- id: diff_params_clause_param_not_differentiable - msg: "can only differentiate with respect to parameters that conform to 'Differentiable', but %0 does not conform to 'Differentiable'" - -- id: found_candidate - msg: "found this candidate" - -- id: found_candidate_type - msg: "found candidate with type %0" - -- id: no_MaxBuiltinFloatType_found - msg: "standard library error: _MaxBuiltinFloatType is not properly defined" - -- id: no_member_of_module - msg: "module %0 has no member named %1" - -- id: super_with_no_base_class - msg: "'super' members cannot be referenced in a root class" - -- id: bad_init_ref_base - msg: "'init' can only refer to the initializers of 'self'%select{| or 'super'}0" - -- id: init_delegation_outside_initializer - msg: "initializer delegation can only occur within an initializer" - -- id: init_delegates_and_chains - msg: "initializer cannot both delegate ('self.init') and chain to a superclass initializer ('super.init')" - -- id: init_delegation_or_chain - msg: "previous %select{delegation|chaining}0 call is here" - -- id: delegating_convenience_super_init - msg: "convenience initializer for %0 must delegate (with 'self.init') rather than chaining to a superclass initializer (with 'super.init')" - -- id: delegating_designated_init - msg: "designated initializer for %0 cannot delegate (with 'self.init'); did you mean this to be a convenience initializer?" - -- id: delegating_designated_init_in_extension - msg: "designated initializer for %0 cannot delegate (with 'self.init')" - -- id: delegation_here - msg: "delegation occurs here" - -- id: chain_convenience_init - msg: "must call a designated initializer of the superclass %0" - -- id: delegate_chain_nonoptional_to_optional - msg: "a non-failable initializer cannot %select{delegate|chain}0 to failable initializer %1 written with 'init?'" - -- id: init_force_unwrap - msg: "force potentially-failing result with '!'" - -- id: init_propagate_failure - msg: "propagate the failure with 'init?'" - -- id: delegate_chain_nonoptional_to_optional_try - msg: "a non-failable initializer cannot use 'try?' to %select{delegate|chain}0 to another initializer" - -- id: init_delegate_force_try - msg: "force potentially-failing result with 'try!'" - -- id: init_delegation_nested - msg: "%select{initializer delegation ('self.init')|initializer chaining ('super.init')}0 cannot be nested in another %select{expression|statement}1" - -- id: convenience_init_here - msg: "convenience initializer is declared here" - -- id: designated_init_in_extension - msg: "designated initializer cannot be declared in an extension of %0; did you mean this to be a convenience initializer?" - -- id: cfclass_designated_init_in_extension - msg: "designated initializer cannot be declared in an extension of %0" - -- id: enumstruct_convenience_init - msg: "delegating initializers in %0 are not marked with 'convenience'" - -- id: nonclass_convenience_init - msg: "convenience initializer not allowed in non-class type %0" - -- id: cfclass_convenience_init - msg: "convenience initializers are not supported in extensions of CF types" - -- id: dynamic_construct_class - msg: "constructing an object of class type %0 with a metatype value must use a 'required' initializer" - -- id: note_nonrequired_initializer - msg: "selected %select{non-required|implicit}0 initializer %1" - -- id: construct_protocol_value - msg: "value of type %0 is a protocol; it cannot be instantiated" - -- id: construct_protocol_by_name - msg: "protocol type %0 cannot be instantiated" - -- id: unknown_binop - msg: "operator is not a known binary operator" - -- id: non_associative_adjacent_operators - msg: "adjacent operators are in non-associative precedence group %0" - -- id: unordered_adjacent_operators - msg: "adjacent operators are in unordered precedence groups %0 and %1" - -- id: missing_builtin_precedence_group - msg: "broken standard library: missing builtin precedence group %0" - -- id: try_rhs - msg: "'%select{try|try!|try?|await}0' cannot appear to the right of a non-assignment operator" - -- id: try_if_rhs_noncovering - msg: "'%select{try|try!|try?|await}0' following conditional operator does not cover everything to its right" - -- id: try_assign_rhs_noncovering - msg: "'%select{try|try!|try?|await}0' following assignment operator does not cover everything to its right" - -- id: broken_bool - msg: "type 'Bool' is broken" - -- id: inject_forced_downcast - msg: "treating a forced downcast to %0 as optional will never produce 'nil'" - -- id: forced_to_conditional_downcast - msg: "use 'as?' to perform a conditional downcast to %0" - -- id: silence_inject_forced_downcast - msg: "add parentheses around the cast to silence this warning" - -- id: conditional_downcast_foreign - msg: "conditional downcast to CoreFoundation type %0 will always succeed" - -- id: note_explicitly_compare_cftypeid - msg: "did you mean to explicitly compare the CFTypeIDs of %0 and %1?" - -- id: optional_used_as_boolean - msg: "optional type %0 cannot be used as a boolean; test for '%select{!|=}1= nil' instead" - -- id: integer_used_as_boolean - msg: "type %0 cannot be used as a boolean; test for '%select{!|=}1= 0' instead" - -- id: interpolation_missing_proto - msg: "string interpolation requires the protocol 'ExpressibleByStringInterpolation' to be defined" - -- id: interpolation_broken_proto - msg: "protocol 'ExpressibleByStringInterpolation' is broken" - -- id: object_literal_broken_proto - msg: "object literal protocol is broken" - -- id: discard_expr_outside_of_assignment - msg: "'_' can only appear in a pattern or on the left side of an assignment" - -- id: discard_expr_void_result_redundant - msg: "using '_' to ignore the result of a Void-returning function is redundant" - -- id: collection_literal_heterogeneous - msg: "heterogeneous collection literal could only be inferred to %0; add explicit type annotation if this is intentional" - -- id: collection_literal_empty - msg: "empty collection literal requires an explicit type" - -- id: unresolved_member_no_inference - msg: "reference to member %0 cannot be resolved without a contextual type" - -- id: cannot_infer_base_of_unresolved_member - msg: "cannot infer contextual base in reference to member %0" - -- id: unresolved_nil_literal - msg: "'nil' requires a contextual type" - -- id: cannot_force_unwrap_nil_literal - msg: "'nil' literal cannot be force unwrapped" - -- id: type_of_expression_is_ambiguous - msg: "type of expression is ambiguous without more context" - -- id: failed_to_produce_diagnostic - msg: "failed to produce diagnostic for expression; please file a bug report" - -- id: missing_protocol - msg: "missing protocol %0" - -- id: nil_literal_broken_proto - msg: "protocol 'ExpressibleByNilLiteral' is broken" - -- id: builtin_integer_literal_broken_proto - msg: "protocol '_ExpressibleByBuiltinIntegerLiteral' is broken" - -- id: integer_literal_broken_proto - msg: "protocol 'ExpressibleByIntegerLiteral' is broken" - -- id: builtin_float_literal_broken_proto - msg: "protocol '_ExpressibleByBuiltinFloatLiteral' is broken" - -- id: float_literal_broken_proto - msg: "protocol 'ExpressibleByFloatLiteral' is broken" - -- id: builtin_boolean_literal_broken_proto - msg: "protocol '_ExpressibleByBuiltinBooleanLiteral' is broken" - -- id: boolean_literal_broken_proto - msg: "protocol 'ExpressibleByBooleanLiteral' is broken" - -- id: builtin_unicode_scalar_literal_broken_proto - msg: "protocol '_ExpressibleByBuiltinUnicodeScalarLiteral' is broken" - -- id: unicode_scalar_literal_broken_proto - msg: "protocol 'ExpressibleByUnicodeScalarLiteral' is broken" - -- id: builtin_extended_grapheme_cluster_literal_broken_proto - msg: "protocol '_ExpressibleByBuiltinExtendedGraphemeClusterLiteral' is broken" - -- id: extended_grapheme_cluster_literal_broken_proto - msg: "protocol 'ExpressibleByExtendedGraphemeClusterLiteral' is broken" - -- id: builtin_string_literal_broken_proto - msg: "protocol '_ExpressibleByBuiltinStringLiteral' is broken" - -- id: string_literal_broken_proto - msg: "protocol 'ExpressibleByStringLiteral' is broken" - -- id: should_use_dictionary_literal - msg: "dictionary of type %0 cannot be %select{used|initialized}1 with array literal" - -- id: meant_dictionary_lit - msg: "did you mean to use a dictionary literal instead?" - -- id: should_use_empty_dictionary_literal - msg: "use [:] to get an empty dictionary literal" - -- id: type_is_not_dictionary - msg: "contextual type %0 cannot be used with dictionary literal" - -- id: cannot_explicitly_specialize_generic_function - msg: "cannot explicitly specialize a generic function" - -- id: not_a_generic_definition - msg: "cannot specialize a non-generic definition" - -- id: not_a_generic_type - msg: "cannot specialize non-generic type %0" - -- id: type_parameter_count_mismatch - msg: "generic type %0 specialized with %select{too many|too few}3 type parameters (got %2, but expected %1)" - -- id: generic_type_requires_arguments - msg: "reference to generic type %0 requires arguments in <...>" - -- id: descriptive_generic_type_declared_here - msg: "%0 declared here" - -- id: use_of_void_pointer - msg: "Unsafe%0Pointer has been replaced by Unsafe%0RawPointer" - -- id: ambiguous_decl_ref - msg: "ambiguous use of %0" - -- id: ambiguous_operator_ref - msg: "ambiguous use of operator %0" - -- id: ambiguous_because_of_trailing_closure - msg: "%select{use an explicit argument label instead of a trailing closure|avoid using a trailing closure}0 to call %1" - -- id: partial_application_of_function_invalid - msg: "partial application of %select{'mutating' method|'super.init' initializer chain|'self.init' initializer delegation|'super' instance method with metatype base}0 is not allowed" - -- id: partial_application_of_function_invalid_swift4 - msg: "partial application of %select{'mutating' method|'super.init' initializer chain|'self.init' initializer delegation|'super' instance method with metatype base}0 is not allowed; calling the function has undefined behavior and will be an error in future Swift versions" - -- id: self_assignment_var - msg: "assigning a variable to itself" - -- id: self_assignment_prop - msg: "assigning a property to itself" - -- id: property_use_in_closure_without_explicit_self - msg: "reference to property %0 in closure requires explicit use of 'self' to make capture semantics explicit" - -- id: method_call_in_closure_without_explicit_self - msg: "call to method %0 in closure requires explicit use of 'self' to make capture semantics explicit" - -- id: note_capture_self_explicitly - msg: "capture 'self' explicitly to enable implicit 'self' in this closure" - -- id: note_reference_self_explicitly - msg: "reference 'self.' explicitly" - -- id: note_other_self_capture - msg: "variable other than 'self' captured here under the name 'self' does not enable implicit 'self'" - -- id: note_self_captured_weakly - msg: "weak capture of 'self' here does not enable implicit 'self'" - -- id: implicit_use_of_self_in_closure - msg: "implicit use of 'self' in closure; use 'self.' to make capture semantics explicit" - -- id: recursive_accessor_reference - msg: "attempting to %select{access|modify}1 %0 within its own %select{getter|setter}1" - -- id: recursive_accessor_reference_silence - msg: "access 'self' explicitly to silence this warning" - -- id: store_in_willset - msg: "attempting to store to property %0 within its own willSet, which is about to be overwritten by the new value" - -- id: value_of_module_type - msg: "expected module member name after module name" - -- id: value_of_metatype_type - msg: "expected member name or constructor call after type name" - -- id: add_parens_to_type - msg: "add arguments after the type to construct a value of the type" - -- id: add_self_to_type - msg: "use '.self' to reference the type object" - -- id: warn_unqualified_access - msg: "use of %0 treated as a reference to %1 in %2 %3" - -- id: fix_unqualified_access_member - msg: "use 'self.' to silence this warning" - -- id: fix_unqualified_access_top_level - msg: "use '%0' to reference the %1" - -- id: fix_unqualified_access_top_level_multi - msg: "use '%0' to reference the %1 in module %2" - -- id: warn_deprecated_conditional_conformance_outer_access - msg: "use of %0 as reference to %1 in %2 %3 will change in future versions of Swift to reference %4 in %5 %6 which comes via a conditional conformance" - -- id: fix_deprecated_conditional_conformance_outer_access - msg: "use '%0' to continue to reference the %1" - -- id: unsupported_special_decl_ref - msg: "referencing %0 as a function value is not implemented" - -- id: bitcasting_away_noescape - msg: "'unsafeBitCast' from non-escaping function type %0 to escaping function type %1 is undefined; use 'withoutActuallyEscaping' to temporarily escape a function" - -- id: bitcasting_to_change_function_rep - msg: "'unsafeBitCast' from function type %0 to %1 changes @convention and is undefined; use an implicit conversion to change conventions" - -- id: bitcasting_to_downcast - msg: "'unsafeBitCast' from %0 to %1 can be replaced with 'unsafeDowncast'" - -- id: bitcasting_is_no_op - msg: "'unsafeBitCast' from %0 to %1 is unnecessary and can be removed" - -- id: bitcasting_to_change_pointer_kind - msg: "'unsafeBitCast' from %0 to %1 can be replaced with %2 initializer" - -- id: bitcasting_to_change_pointee_type - msg: "'unsafeBitCast' from %0 to %1 changes pointee type and may lead to undefined behavior; use the 'withMemoryRebound' method on %0 to rebind the type of memory" - -- id: bitcasting_to_give_type_to_raw_pointer - msg: "'unsafeBitCast' from %0 to %1 gives a type to a raw pointer and may lead to undefined behavior" - -- id: bitcast_assume_memory_rebound - msg: "use the 'assumingMemoryBound' method if the pointer is known to point to an existing value or array of type %0 in memory" - -- id: bitcast_bind_memory - msg: "use the 'bindMemory' method to assign type %0 to uninitialized raw memory" - -- id: bitcasting_for_number_bit_pattern_init - msg: "'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern:' initializer on %1" - -- id: bitcasting_for_number_bit_pattern_property - msg: "'unsafeBitCast' from %0 to %1 can be replaced with 'bitPattern' property on %0" - -- id: bitcasting_to_change_from_unsized_to_sized_int - msg: "'unsafeBitCast' from %0 to %1 can be replaced with %1 initializer" - -- id: use_of_qq_on_non_optional_value - msg: "left side of nil coalescing operator '??' has non-optional type %0, so the right side is never used" - -- id: nonoptional_compare_to_nil - msg: "comparing non-optional value of type %0 to 'nil' always returns %select{false|true}1" - -- id: optional_check_nonoptional - msg: "non-optional expression of type %0 used in a check for optionals" - -- id: optional_check_promotion - msg: "explicitly specified type %0 adds an additional level of optional to the initializer, making the optional check always succeed" - -- id: optional_pattern_match_promotion - msg: "pattern match introduces an implicit promotion from %0 to %1" - -- id: optional_to_any_coercion - msg: "expression implicitly coerced from %0 to %1" - -- id: iuo_to_any_coercion - msg: "coercion of implicitly unwrappable value of type %0 to %1 does not unwrap optional" - -- id: iuo_to_any_coercion_note - msg: "implicitly unwrapped %0 %1 declared here" - -- id: iuo_to_any_coercion_note_func_result - msg: "%0 %1 with implicitly unwrapped result type is declared here" - -- id: default_optional_to_any - msg: "provide a default value to avoid this warning" - -- id: force_optional_to_any - msg: "force-unwrap the value to avoid this warning" - -- id: silence_optional_to_any - msg: "explicitly cast to %0 with '%1' to silence this warning" - -- id: debug_description_in_string_interpolation_segment - msg: "string interpolation produces a debug description for %select{an optional|a function}0 value; did you mean to make this explicit?" - -- id: silence_debug_description_in_interpolation_segment_call - msg: "use 'String(describing:)' to silence this warning" - -- id: noescape_parameter - msg: "parameter %0 is implicitly non-escaping" - -- id: generic_parameters_always_escaping - msg: "generic parameters are always considered '@escaping'" - -- id: passing_noescape_to_escaping - msg: "passing non-escaping parameter %0 to function expecting an @escaping closure" - -- id: converting_noespace_param_to_generic_type - msg: "converting non-escaping parameter %0 to generic parameter %1 may allow it to escape" - -- id: assigning_noescape_to_escaping - msg: "assigning non-escaping parameter %0 to an @escaping closure" - -- id: general_noescape_to_escaping - msg: "using non-escaping parameter %0 in a context expecting an @escaping closure" - -- id: converting_noescape_to_type - msg: "converting non-escaping value to %0 may allow it to escape" - -- id: capture_across_type_decl - msg: "%0 declaration cannot close over value %1 defined in outer scope" - -- id: jump_out_of_defer - msg: "'%0' cannot transfer control out of a defer statement" - -- id: defer_stmt_at_block_end - msg: "'defer' statement at end of scope always executes immediately; replace with 'do' statement to silence this warning" - -- id: return_invalid_outside_func - msg: "return invalid outside of a func" - -- id: return_expr_missing - msg: "non-void function should return a value" - -- id: return_non_failable_init - msg: "only a failable initializer can return 'nil'" - -- id: make_init_failable - msg: "use 'init?' to make the initializer %0 failable" - -- id: return_init_non_nil - msg: "'nil' is the only return value permitted in an initializer" - -- id: if_always_true - msg: "'if' condition is always true" - -- id: while_always_true - msg: "'while' condition is always true" - -- id: guard_always_succeeds - msg: "'guard' condition is always true, body is unreachable" - -- id: expression_unused_closure - msg: "closure expression is unused" - -- id: expression_unused_function - msg: "expression resolves to an unused function" - -- id: expression_unused_lvalue - msg: "expression resolves to an unused %select{variable|property|subscript}0" - -- id: expression_unused_result_call - msg: "result of call to %0 is unused" - -- id: expression_unused_result_operator - msg: "result of operator %0 is unused" - -- id: expression_unused_result_unknown - msg: "result of call to %select{function|closure}0 returning %1 is unused" - -- id: expression_unused_result - msg: "expression of type %0 is unused" - -- id: expression_unused_init_result - msg: "result of %0 initializer is unused" - -- id: expression_unused_optional_try - msg: "result of 'try?' is unused" - -- id: expression_unused_selector_result - msg: "result of '#selector' is unused" - -- id: expression_unused_literal - msg: "%0 literal is unused" - -- id: assignment_lhs_not_lvalue - msg: "cannot assign to immutable expression of type %0" - -- id: assignment_lhs_is_apply_expression - msg: "expression is not assignable: %0" - -- id: assignment_lhs_is_immutable_variable - msg: "cannot assign to value: %0" - -- id: assignment_lhs_is_immutable_property - msg: "cannot assign to property: %0" - -- id: assignment_subscript_has_immutable_base - msg: "cannot assign through subscript: %0" - -- id: assignment_dynamic_property_has_immutable_base - msg: "cannot assign through dynamic lookup property: %0" - -- id: assignment_bang_has_immutable_subcomponent - msg: "cannot assign through '!': %0" - -- id: candidate_is_not_assignable - msg: "candidate is not assignable: %0 %1" - -- id: change_to_mutating - msg: "mark %select{method|accessor}0 'mutating' to make 'self' mutable" - -- id: masked_mutable_property - msg: "add explicit '%0' to refer to mutable %1 of %2" - -- id: assignment_let_property_delegating_init - msg: "'let' property %0 may not be initialized directly; use \"self.init(...)\" or \"self = ...\" instead" - -- id: label_shadowed - msg: "label %0 cannot be reused on an inner statement" - -- id: break_outside_loop - msg: "'break' is only allowed inside a loop, if, do, or switch" - -- id: unlabeled_break_outside_loop - msg: "unlabeled 'break' is only allowed inside a loop or switch, a labeled break is required to exit an if or do" - -- id: continue_outside_loop - msg: "'continue' is only allowed inside a loop" - -- id: continue_not_in_this_stmt - msg: "'continue' cannot be used with %0 statements" - -- id: unresolved_label - msg: "cannot find label %0 in scope" - -- id: unresolved_label_corrected - msg: "cannot find label %0 in scope; did you mean %1?" - -- id: foreach_sequence_does_not_conform_to_expected_protocol - msg: "for-in loop requires %0 to conform to %1%select{|; did you mean to unwrap optional?}2" - -- id: no_match_operator - msg: "no binary '~=' operator available for 'switch' statement" - -- id: fallthrough_outside_switch - msg: "'fallthrough' is only allowed inside a switch" - -- id: fallthrough_from_last_case - msg: "'fallthrough' without a following 'case' or 'default' block" - -- id: fallthrough_into_case_with_var_binding - msg: "'fallthrough' from a case which doesn't bind variable %0" - -- id: unnecessary_cast_over_optionset - msg: "unnecessary cast over raw value of %0" - -- id: mutability_mismatch_multiple_pattern_list - msg: "'%select{var|let}0' pattern binding must match previous '%select{var|let}1' pattern binding" - -- id: type_mismatch_multiple_pattern_list - msg: "pattern variable bound to type %0, expected type %1" - -- id: type_mismatch_fallthrough_pattern_list - msg: "pattern variable bound to type %0, fallthrough case bound to type %1" - -- id: unknown_case_must_be_catchall - msg: "'@unknown' is only supported for catch-all cases (\"case _\")" - -- id: unknown_case_where_clause - msg: "'where' cannot be used with '@unknown'" - -- id: unknown_case_multiple_patterns - msg: "'@unknown' cannot be applied to multiple patterns" - -- id: unknown_case_must_be_last - msg: "'@unknown' can only be applied to the last case in a switch" - -- id: where_on_one_item - msg: "'where' only applies to the second pattern match in this case" - -- id: add_where_newline - msg: "disambiguate by adding a line break between them if this is desired" - -- id: duplicate_where - msg: "duplicate the 'where' on both patterns to check both patterns" - -- id: trailing_closure_requires_parens - msg: "trailing closure in this context is confusable with the body of the statement; pass as a parenthesized argument to silence this warning" - -- id: opaque_type_var_no_init - msg: "property declares an opaque return type, but has no initializer expression from which to infer an underlying type" - -- id: opaque_type_no_underlying_type_candidates - msg: "function declares an opaque return type, but has no return statements in its body from which to infer an underlying type" - -- id: opaque_type_mismatched_underlying_type_candidates - msg: "function declares an opaque return type, but the return statements in its body do not have matching underlying types" - -- id: opaque_type_underlying_type_candidate_here - msg: "return statement has underlying type %0" - -- id: opaque_type_self_referential_underlying_type - msg: "function opaque return type was inferred as %0, which defines the opaque type in terms of itself" - -- id: opaque_type_var_no_underlying_type - msg: "property declares an opaque return type, but cannot infer the underlying type from its initializer expression" - -- id: cannot_infer_type_for_pattern - msg: "type annotation missing in pattern" - -- id: refutable_pattern_requires_initializer - msg: "pattern matching requires an initializer value to match against" - -- id: var_pattern_didnt_bind_variables - msg: "'%0' pattern has no effect; sub-pattern didn't bind any variables" - -- id: iflet_pattern_matching - msg: "pattern matching in a condition requires the 'case' keyword" - -- id: iflet_implicitly_unwraps - msg: "pattern matching in a condition implicitly unwraps optionals" - -- id: type_pattern_missing_is - msg: "'is' keyword required to pattern match against type name" - -- id: pattern_type_mismatch_context - msg: "type annotation does not match contextual type %0" - -- id: tuple_pattern_in_non_tuple_context - msg: "tuple pattern cannot match values of the non-tuple type %0" - -- id: found_one_pattern_for_several_associated_values - msg: "enum case '%0' has %1 associated values; matching them as a tuple is deprecated" - -- id: converting_tuple_into_several_associated_values - msg: "enum case '%0' has %1 associated values" - -- id: converting_several_associated_values_into_tuple - msg: "enum case '%0' has one associated value that is a tuple of %1 elements" - -- id: closure_argument_list_tuple - msg: "contextual closure type %0 expects %1 argument%s1, but %2 %select{were|was}3 used in closure body" - -- id: closure_argument_list_missing - msg: "contextual type for closure argument list expects %0 argument%s0, which cannot be implicitly ignored" - -- id: closure_tuple_parameter_destructuring - msg: "closure tuple parameter %0 does not support destructuring" - -- id: closure_tuple_parameter_destructuring_implicit - msg: "closure tuple parameter %0 does not support destructuring with implicit parameters" - -- id: single_tuple_parameter_mismatch_special - msg: "%0 expects a single parameter of type %1%2" - -- id: single_tuple_parameter_mismatch_normal - msg: "%0 %1 expects a single parameter of type %2%3" - -- id: cannot_convert_single_tuple_into_multiple_arguments - msg: "%0 %select{%1 |}2expects %3 separate arguments%select{|; remove extra parentheses to change tuple into separate arguments}4" - -- id: enum_element_pattern_assoc_values_mismatch - msg: "pattern with associated values does not match enum case %0" - -- id: enum_element_pattern_assoc_values_remove - msg: "remove associated values to make the pattern match" - -- id: tuple_pattern_length_mismatch - msg: "tuple pattern has the wrong length for tuple type %0" - -- id: tuple_pattern_label_mismatch - msg: "tuple pattern element label %0 must be %1" - -- id: enum_element_pattern_member_not_found - msg: "enum case %0 not found in type %1" - -- id: optional_element_pattern_not_valid_type - msg: "'?' pattern cannot match values of type %0" - -- id: condition_optional_element_pattern_not_valid_type - msg: "initializer for conditional binding must have Optional type, not %0" - -- id: enum_element_pattern_not_member_of_enum - msg: "enum case %0 is not a member of type %1" - -- id: ambiguous_enum_pattern_type - msg: "generic enum type %0 is ambiguous without explicit generic parameters when matching value of type %1" - -- id: type_inferred_to_undesirable_type - msg: "%select{variable|constant}2 %0 inferred to have type %1, which may be unexpected" - -- id: type_inferred_to_uninhabited_type - msg: "%select{variable|constant}2 %0 inferred to have type %1, which is an enum with no cases" - -- id: type_inferred_to_uninhabited_tuple_type - msg: "%select{variable|constant}2 %0 inferred to have type %1, which contains an enum with no cases" - -- id: add_explicit_type_annotation_to_silence - msg: "add an explicit type annotation to silence this warning" - -- id: unowned_assignment_immediate_deallocation - msg: "instance will be immediately deallocated because %select{variable|property}2 %0 is %1" - -- id: unowned_assignment_requires_strong - msg: "a strong reference is required to prevent the instance from being deallocated" - -- id: isa_collection_downcast_pattern_value_unimplemented - msg: "collection downcast in cast pattern is not implemented; use an explicit downcast to %0 instead" - -- id: try_unhandled - msg: "errors thrown from here are not handled" - -- id: throwing_call_unhandled - msg: "call can throw, but the error is not handled" - -- id: tryless_throwing_call_unhandled - msg: "call can throw, but it is not marked with 'try' and the error is not handled" - -- id: throw_in_nonthrowing_function - msg: "error is not handled because the enclosing function is not declared 'throws'" - -- id: throwing_call_in_rethrows_function - msg: "call can throw, but the error is not handled; a function declared 'rethrows' may only throw if its parameter does" - -- id: tryless_throwing_call_in_rethrows_function - msg: "call can throw, but it is not marked with 'try' and the error is not handled; a function declared 'rethrows' may only throw if its parameter does" - -- id: throw_in_rethrows_function - msg: "a function declared 'rethrows' may only throw if its parameter does" - -- id: because_rethrows_argument_throws - msg: "call is to 'rethrows' function, but argument function can throw" - -- id: because_rethrows_default_argument_throws - msg: "call is to 'rethrows' function, but a defaulted argument function can throw" - -- id: throwing_call_in_nonthrowing_autoclosure - msg: "call can throw, but it is executed in a non-throwing autoclosure" - -- id: tryless_throwing_call_in_nonthrowing_autoclosure - msg: "call can throw, but it is not marked with 'try' and it is executed in a non-throwing autoclosure" - -- id: throw_in_nonthrowing_autoclosure - msg: "error is not handled because it is thrown in a non-throwing autoclosure" - -- id: try_unhandled_in_nonexhaustive_catch - msg: "errors thrown from here are not handled because the enclosing catch is not exhaustive" - -- id: throwing_call_in_nonexhaustive_catch - msg: "call can throw, but the enclosing catch is not exhaustive" - -- id: tryless_throwing_call_in_nonexhaustive_catch - msg: "call can throw, but it is not marked with 'try' and the enclosing catch is not exhaustive" - -- id: throw_in_nonexhaustive_catch - msg: "error is not handled because the enclosing catch is not exhaustive" - -- id: throwing_call_in_illegal_context - msg: "call can throw, but errors cannot be thrown out of %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" - -- id: throw_in_illegal_context - msg: "errors cannot be thrown out of %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" - -- id: throwing_operator_without_try - msg: "operator can throw but expression is not marked with 'try'" - -- id: throwing_interpolation_without_try - msg: "interpolation can throw but is not marked with 'try'" - -- id: throwing_call_without_try - msg: "call can throw but is not marked with 'try'" - -- id: note_forgot_try - msg: "did you mean to use 'try'?" - -- id: note_error_to_optional - msg: "did you mean to handle error as optional value?" - -- id: note_disable_error_propagation - msg: "did you mean to disable error propagation?" - -- id: no_throw_in_try - msg: "no calls to throwing functions occur within 'try' expression" - -- id: no_throw_in_do_with_catch - msg: "'catch' block is unreachable because no errors are thrown in 'do' block" - -- id: async_call_without_await - msg: "call is 'async' but is not marked with 'await'" - -- id: async_call_without_await_in_autoclosure - msg: "call is 'async' in an autoclosure argument that is not marked with 'await'" - -- id: no_async_in_await - msg: "no calls to 'async' functions occur within 'await' expression" - -- id: async_call_in_illegal_context - msg: "'async' call cannot occur in %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" - -- id: await_in_illegal_context - msg: "'await' operation cannot occur in %select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0" - -- id: async_in_nonasync_function - msg: "%select{'async'|'await'}0 in %select{a function|an autoclosure}1 that does not support concurrency" - -- id: note_add_async_to_function - msg: "add 'async' to function %0 to make it asynchronous" - -- id: note_add_asynchandler_to_function - msg: "add '@asyncHandler' to function %0 to create an implicit asynchronous context" - -- id: not_objc_function_async - msg: "'async' function cannot be represented in Objective-C" - -- id: not_objc_function_type_async - msg: "'async' function types cannot be represented in Objective-C" - -- id: protocol_witness_async_conflict - msg: "candidate is %select{not |}0'async', but protocol requirement is%select{| not}0" - -- id: async_autoclosure_nonasync_function - msg: "'async' autoclosure parameter in a non-'async' function" - -- id: asynchandler_attr_requires_concurrency - msg: "'@asyncHandler' is only valid when experimental concurrency is enabled" - -- id: asynchandler_non_func - msg: "'@asyncHandler' can only be applied to functions" - -- id: asynchandler_returns_value - msg: "'@asyncHandler' function can only return 'Void'" - -- id: asynchandler_throws - msg: "'@asyncHandler' function cannot throw" - -- id: asynchandler_async - msg: "'@asyncHandler' function cannot be 'async' itself" - -- id: asynchandler_inout_parameter - msg: "'inout' parameter is not allowed in '@asyncHandler' function" - -- id: asynchandler_mutating - msg: "'@asyncHandler' function cannot be 'mutating'" - -- id: unsupported_recursive_struct - msg: "value type %0 cannot have a stored property that recursively contains it" - -- id: enum_non_well_founded - msg: "enum containing only recursive cases is impossible to instantiate" - -- id: recursive_enum_not_indirect - msg: "recursive enum %0 is not marked 'indirect'" - -- id: unsupported_infinitely_sized_type - msg: "value type %0 has infinite size" - -- id: note_type_cycle_starts_here - msg: "cycle beginning here: %0" - -- id: note_recursive_enum_case_here - msg: "recursive case here" - -- id: sugar_type_not_found - msg: "broken standard library: cannot find %select{Array|Optional|ImplicitlyUnwrappedOptional|Dictionary|Error}0 type" - -- id: optional_intrinsics_not_found - msg: "broken standard library: cannot find intrinsic operations on Optional" - -- id: pointer_argument_intrinsics_not_found - msg: "broken standard library: cannot find intrinsic operations on UnsafeMutablePointer" - -- id: array_literal_intrinsics_not_found - msg: "broken standard library: cannot find intrinsic operations on Array" - -- id: class_super_access - msg: "class %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}3|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 because its superclass %select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 type as a generic parameter}4" - -- id: class_super_access_warn - msg: "class %select{should be declared %select{private|fileprivate|internal|%error|%error}1|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 because its superclass %select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2|uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 type as a generic parameter}4" - -- id: class_super_not_usable_from_inline - msg: "%select{type referenced from |}0the superclass of a '@usableFromInline' class must be '@usableFromInline' or public" - -- id: class_super_not_usable_from_inline_warn - msg: "%select{type referenced from |}0the superclass of a '@usableFromInline' class should be '@usableFromInline' or public" - -- id: dot_protocol_on_non_existential - msg: "cannot use 'Protocol' with non-protocol type %0" - -- id: tuple_single_element - msg: "cannot create a single-element tuple with an element label" - -- id: tuple_ellipsis - msg: "cannot create a variadic tuple" - -- id: tuple_duplicate_label - msg: "cannot create a tuple with a duplicate element label" - -- id: enum_element_ellipsis - msg: "variadic enum cases are not supported" - -- id: implicitly_unwrapped_optional_in_illegal_position_interpreted_as_optional - msg: "using '!' is not allowed here; treating this as '?' instead" - -- id: implicitly_unwrapped_optional_deprecated_in_this_position - msg: "using '!' here is deprecated and will be removed in a future release" - -- id: implicitly_unwrapped_optional_in_illegal_position - msg: "using '!' is not allowed here; perhaps '?' was intended?" - -- id: invalid_ownership_type - msg: "%0 may only be applied to class and class-bound protocol types, not %1" - -- id: invalid_ownership_protocol_type - msg: "%0 must not be applied to non-class-bound %1; consider adding a protocol conformance that has a class bound" - -- id: invalid_ownership_incompatible_class - msg: "%0 is incompatible with %1 references" - -- id: invalid_ownership_with_optional - msg: "%0 variable cannot have optional type" - -- id: invalid_ownership_not_optional - msg: "%0 variable should have optional type %1" - -- id: invalid_ownership_is_let - msg: "%0 must be a mutable variable, because it may change at runtime" - -- id: ownership_invalid_in_protocols - msg: "%0 cannot be applied to a property declaration in a protocol" - -- id: ownership_invalid_in_protocols_compat_warning - msg: "%0 should not be applied to a property declaration in a protocol and will be disallowed in future versions" - -- id: required_initializer_nonclass - msg: "'required' initializer in non-class type %0" - -- id: required_initializer_in_extension - msg: "'required' initializer must be declared directly in class %0 (not in an extension)" - -- id: required_initializer_missing - msg: "'required' initializer %0 must be provided by subclass of %1" - -- id: required_initializer_here - msg: "'required' initializer is declared in superclass here" - -- id: required_initializer_not_accessible - msg: "'required' initializer must be accessible wherever class %0 can be subclassed" - -- id: required_initializer_missing_keyword - msg: "'required' modifier must be present on all overrides of a required initializer" - -- id: required_initializer_override_wrong_keyword - msg: "use the 'required' modifier to override a required initializer" - -- id: required_initializer_override_keyword - msg: "'override' is implied when overriding a required initializer" - -- id: overridden_required_initializer_here - msg: "overridden required initializer is here" - -- id: attribute_requires_function_type - msg: "@%0 attribute only applies to function types" - -- id: unsupported_convention - msg: "convention '%0' not supported" - -- id: unreferenced_generic_parameter - msg: "generic parameter '%0' is not used in function signature" - -- id: unexpected_ctype_for_non_c_convention - msg: "convention '%0' does not support the 'cType' argument label, did you mean @convention(c, cType: \"%1\") or @convention(block, cType: \"%1\") instead?" - -- id: unable_to_parse_c_function_type - msg: "unable to parse '%0'; it should be a C function pointer type or a block pointer type" - -- id: unsupported_opaque_type - msg: "'some' types are only implemented for the declared type of properties and subscripts and the return type of functions" - -- id: opaque_type_unsupported_pattern - msg: "'some' type can only be declared on a single property declaration" - -- id: opaque_type_in_protocol_requirement - msg: "'some' type cannot be the return type of a protocol requirement; did you mean to add an associated type?" - -- id: attr_only_on_parameters_of_differentiable - msg: "'%0' may only be used on parameters of '@differentiable' function types" - -- id: differentiable_function_type_invalid_parameter - msg: "parameter type '%0' does not conform to 'Differentiable'%select{| and satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is '@differentiable%select{|(linear)}1'%select{|; did you want to add '@noDerivative' to this parameter?}2" - -- id: differentiable_function_type_invalid_result - msg: "result type '%0' does not conform to 'Differentiable'%select{| and satisfy '%0 == %0.TangentVector'}1, but the enclosing function type is '@differentiable%select{|(linear)}1'" - -- id: opened_non_protocol - msg: "@opened cannot be applied to non-protocol type %0" - -- id: sil_function_ellipsis - msg: "SIL function types cannot be variadic" - -- id: sil_function_input_label - msg: "SIL function types cannot have labeled inputs" - -- id: sil_function_output_label - msg: "SIL function types cannot have labeled results" - -- id: sil_non_coro_yields - msg: "non-coroutine SIL function types cannot have @yield results" - -- id: sil_function_repeat_convention - msg: "repeated %select{parameter|result|callee}0 convention attribute" - -- id: ast_subst_function_type - msg: "substitutions cannot be provided on a formal function type" - -- id: sil_function_multiple_error_results - msg: "SIL function types cannot have multiple @error results" - -- id: unsupported_sil_convention - msg: "convention '%0' not supported in SIL" - -- id: illegal_sil_type - msg: "type %0 is not a legal SIL value type" - -- id: sil_box_arg_mismatch - msg: "SIL box type has wrong number of generic arguments for layout" - -- id: sil_metatype_without_repr - msg: "metatypes in SIL must have @thin, @thick, or @objc_metatype attribute" - -- id: sil_metatype_multiple_reprs - msg: "metatypes in SIL can only be one of @thin, @thick, or @objc_metatype" - -- id: objc_interop_disabled - msg: "Objective-C interoperability is disabled" - -- id: attr_used_without_required_module - msg: "%0 attribute used without importing module %1" - -- id: invalid_objc_decl_context - msg: "@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes" - -- id: invalid_objc_decl - msg: "only classes (and their extensions), protocols, methods, initializers, properties, and subscript declarations can be declared @objc" - -- id: invalid_objc_swift_rooted_class - msg: "only classes that inherit from NSObject can be declared @objc" - -- id: invalid_nonobjc_decl - msg: "only class members and extensions of classes can be declared @nonobjc" - -- id: invalid_nonobjc_extension - msg: "only extensions of classes can be declared @nonobjc" - -- id: objc_in_extension_context - msg: "members of constrained extensions cannot be declared @objc" - -- id: objc_in_generic_extension - msg: "extensions of %select{classes from generic context|generic classes}0 cannot contain '@objc' members" - -- id: objc_in_resilient_extension - msg: "'@objc' %0 in extension of subclass of %1 requires %2 %3" - -- id: objc_operator - msg: "operator methods cannot be declared @objc" - -- id: objc_operator_proto - msg: "@objc protocols must not have operator requirements" - -- id: objc_inference_swift3_dynamic - msg: "inference of '@objc' for 'dynamic' members is deprecated" - -- id: objc_inference_swift3_objc_derived - msg: "inference of '@objc' for members of Objective-C-derived classes is deprecated" - -- id: objc_inference_swift3_addobjc - msg: "add '@objc' to continue exposing an Objective-C entry point (Swift 3 behavior)" - -- id: objc_inference_swift3_addnonobjc - msg: "add '@nonobjc' to suppress the Objective-C entry point (Swift 4 behavior)" - -- id: objc_for_generic_class - msg: "generic subclasses of '@objc' classes cannot have an explicit '@objc' because they are not directly visible from Objective-C" - -- id: objc_for_resilient_class - msg: "explicit '@objc' on subclass of %0 requires %1 %2" - -- id: objc_getter_for_nonobjc_property - msg: "'@objc' getter for non-'@objc' property" - -- id: objc_getter_for_nonobjc_subscript - msg: "'@objc' getter for non-'@objc' subscript" - -- id: objc_setter_for_nonobjc_property - msg: "'@objc' setter for non-'@objc' property" - -- id: objc_setter_for_nonobjc_subscript - msg: "'@objc' setter for non-'@objc' subscript" - -- id: accessor_swift3_objc_inference - msg: "%select{%0 %1|%1}2 with '@objc' %select{getter|setter}3 depends on deprecated inference of '@objc'" - -- id: objc_enum_generic - msg: "'@objc' enum cannot be generic" - -- id: objc_name_req_nullary - msg: "'@objc' %0 must have a simple name" - -- id: objc_name_subscript - msg: "'@objc' subscript cannot have a name; did you mean to put the name on the getter or setter?" - -- id: objc_name_deinit - msg: "'@objc' deinitializer cannot have a name" - -- id: objc_name_func_mismatch - msg: "'@objc' %select{initializer|method}0 name provides %select{one argument name|names for %1 arguments}2, but %select{initializer|method}0 has %select{one parameter|%3 parameters}4%select{| (%select{|including }4the error parameter)}5" - -- id: objc_enum_case_req_name - msg: "attribute has no effect; cases within an '@objc' enum are already exposed to Objective-C" - -- id: objc_enum_case_req_objc_enum - msg: "'@objc' enum case is not allowed outside of an '@objc' enum" - -- id: objc_enum_case_multi - msg: "'@objc' enum case declaration defines multiple enum cases with the same Objective-C name" - -- id: objc_extension_not_class - msg: "'@objc' can only be applied to an extension of a class" - -- id: attribute_meaningless_when_nonobjc - msg: "'@%0' attribute is meaningless on a property that cannot be represented in Objective-C" - -- id: objc_invalid_on_var - msg: "property cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because its type cannot be represented in Objective-C" - -- id: objc_invalid_on_subscript - msg: "subscript cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because its type cannot be represented in Objective-C" - -- id: objc_invalid_on_static_subscript - msg: "%0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1" - -- id: objc_invalid_with_generic_params - msg: "%0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1 because it has generic parameters" - -- id: objc_convention_invalid - msg: "%0 is not representable in Objective-C, so it cannot be used with '@convention(%1)'" - -- id: paren_void_probably_void - msg: "when calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?" - -- id: not_objc_empty_protocol_composition - msg: "'Any' is not considered '@objc'; use 'AnyObject' instead" - -- id: not_objc_protocol - msg: "protocol-constrained type containing protocol %0 cannot be represented in Objective-C" - -- id: not_objc_class_constraint - msg: "protocol-constrained type containing class %0 cannot be represented in Objective-C" - -- id: not_objc_error_protocol_composition - msg: "protocol-constrained type containing 'Error' cannot be represented in Objective-C" - -- id: not_objc_empty_tuple - msg: "empty tuple type cannot be represented in Objective-C" - -- id: not_objc_tuple - msg: "tuples cannot be represented in Objective-C" - -- id: not_objc_swift_class - msg: "classes not annotated with @objc cannot be represented in Objective-C" - -- id: not_objc_swift_struct - msg: "Swift structs cannot be represented in Objective-C" - -- id: not_objc_swift_enum - msg: "non-'@objc' enums cannot be represented in Objective-C" - -- id: not_objc_generic_type_param - msg: "generic type parameters cannot be represented in Objective-C" - -- id: not_objc_function_type_param - msg: "function types cannot be represented in Objective-C unless their parameters and returns can be" - -- id: not_objc_function_type_throwing - msg: "throwing function types cannot be represented in Objective-C" - -- id: objc_inferring_on_objc_protocol_member - msg: "inferring '@objc' because the declaration is a member of an '@objc' protocol" - -- id: objc_overriding_objc_decl - msg: "overriding '@objc' %select{property|subscript|initializer|method}0 %1 here" - -- id: objc_witness_objc_requirement - msg: "satisfying requirement for %0 %1 in protocol %2" - -- id: witness_swift3_objc_inference - msg: "use of %0 %1 to satisfy a requirement of protocol %2 depends on '@objc' inference deprecated in Swift 4" - -- id: no_opaque_return_type_of - msg: "unable to resolve type for _opaqueReturnTypeOf attribute" - -- id: objc_observing_accessor - msg: "observing accessors are not allowed to be marked @objc" - -- id: objc_addressor - msg: "addressors are not allowed to be marked @objc" - -- id: objc_coroutine_accessor - msg: "'read' and 'modify' accessors are not allowed to be marked @objc" - -- id: objc_invalid_on_func_variadic - msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because it has a variadic parameter" - -- id: objc_invalid_on_func_inout - msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because inout parameters cannot be represented in Objective-C" - -- id: objc_invalid_on_func_param_type - msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1 because the type of the parameter %0 cannot be represented in Objective-C" - -- id: objc_invalid_on_func_single_param_type - msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because the type of the parameter cannot be represented in Objective-C" - -- id: objc_invalid_on_func_result_type - msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because its result type cannot be represented in Objective-C" - -- id: objc_invalid_on_foreign_class - msg: "method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because Core Foundation types are not classes in Objective-C" - -- id: objc_invalid_on_throwing_optional_result - msg: "throwing method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because it returns a value of optional type %1; 'nil' indicates failure to Objective-C" - -- id: objc_invalid_on_throwing_result - msg: "throwing method cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because it returns a value of type %1; return 'Void' or a type that bridges to an Objective-C class" - -- id: objc_invalid_on_failing_init - msg: "a failable and throwing initializer cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0 because 'nil' indicates failure to Objective-C" - -- id: objc_in_objc_runtime_visible - msg: "%0 cannot be %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}1 because class %2 is only visible via the Objective-C runtime" - -- id: objc_override_method_selector_mismatch - msg: "Objective-C method has a different selector from the method it overrides (%0 vs. %1)" - -- id: objc_override_property_name_mismatch - msg: "Objective-C property has a different name from the property it overrides (%0 vs. %1)" - -- id: objc_ambiguous_inference - msg: "ambiguous inference of Objective-C name for %0 %1 (%2 vs %3)" - -- id: objc_ambiguous_inference_candidate - msg: "%0 (in protocol %1) provides Objective-C name %2" - -- id: objc_ambiguous_error_convention - msg: "%0 overrides or implements protocol requirements for Objective-C declarations with incompatible error argument conventions" - -- id: objc_ambiguous_error_convention_candidate - msg: "%0 provides an error argument here" - -- id: nonlocal_bridged_to_objc - msg: "conformance of %0 to %1 can only be written in module %2" - -- id: missing_bridging_function - msg: "missing '%select{_forceBridgeFromObjectiveC|_conditionallyBridgeFromObjectiveC}0'" - -- id: objc_redecl - msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 with Objective-C selector %4 conflicts with %select{initializer %3|implicit initializer %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript getter|setter for %3|subscript setter}2 with the same Objective-C selector" - -- id: objc_declared_here - msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 declared here" - -- id: objc_redecl_same - msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 with Objective-C selector %2 conflicts with previous declaration with the same Objective-C selector" - -- id: objc_override_other - msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 with Objective-C selector %4 conflicts with %select{initializer %3|implicit initializer %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript getter|setter for %3|subscript setter}2 from superclass %5 with the same Objective-C selector" - -- id: objc_class_method_not_permitted - msg: "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 defines Objective-C class method %2, which is not permitted by Swift" - -- id: objc_witness_selector_mismatch - msg: "Objective-C method %2 provided by %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 does not match the requirement's selector (%3)" - -- id: objc_optional_requirement_conflict - msg: "Objective-C method %4 provided by %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 conflicts with optional requirement %select{initializer %3|implicit initializer %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript getter|setter for %3|subscript setter}2 in protocol %5" - -- id: objc_optional_requirement_swift_rename - msg: "rename %select{method|initializer|property|subscript}0 to match requirement %1" - -- id: witness_non_objc - msg: "non-'@objc' %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 does not satisfy requirement of '@objc' protocol %2" - -- id: witness_non_objc_optional - msg: "non-'@objc' %select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0 does not satisfy optional requirement of '@objc' protocol %2" - -- id: witness_non_objc_storage - msg: "non-'@objc' %select{property %1|subscript}0 does not satisfy requirement of '@objc' protocol %2" - -- id: witness_non_objc_storage_optional - msg: "non-'@objc' %select{property %1|subscript}0 does not satisfy optional requirement of '@objc' protocol %2" - -- id: nonobjc_not_allowed - msg: "declaration is %select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}0, and cannot be marked @nonobjc" - -- id: borrowed_with_objc_dynamic - msg: "%0 cannot be '@_borrowed' if it is '@objc dynamic'" - -- id: borrowed_on_objc_protocol_requirement - msg: "%0 cannot be '@_borrowed' if it is an @objc protocol requirement" - -- id: dynamic_with_transparent - msg: "a declaration cannot be both '@_tranparent' and 'dynamic'" - -- id: dynamic_replacement_accessor_type_mismatch - msg: "replaced accessor %0's type does not match" - -- id: dynamic_replacement_accessor_not_dynamic - msg: "replaced accessor for %0 is not marked dynamic" - -- id: dynamic_replacement_accessor_not_explicit - msg: "replaced accessor %select{get|set|_read|_modify|willSet|didSet|unsafeAddress|addressWithOwner|addressWithNativeOwner|unsafeMutableAddress|mutableAddressWithOwner|}0 for %1 is not explicitly defined" - -- id: dynamic_replacement_function_not_dynamic - msg: "replaced function %0 is not marked dynamic" - -- id: dynamic_replacement_function_not_found - msg: "replaced function %0 could not be found" - -- id: dynamic_replacement_accessor_not_found - msg: "replaced accessor for %0 could not be found" - -- id: dynamic_replacement_accessor_ambiguous - msg: "replaced accessor for %0 occurs in multiple places" - -- id: dynamic_replacement_accessor_ambiguous_candidate - msg: "candidate accessor found in module %0" - -- id: dynamic_replacement_function_of_type_not_found - msg: "replaced function %0 of type %1 could not be found" - -- id: dynamic_replacement_found_function_of_type - msg: "found function %0 of type %1" - -- id: dynamic_replacement_not_in_extension - msg: "dynamicReplacement(for:) of %0 is not defined in an extension or at the file level" - -- id: dynamic_replacement_must_not_be_dynamic - msg: "dynamicReplacement(for:) of %0 must not be dynamic itself" - -- id: dynamic_replacement_replaced_not_objc_dynamic - msg: "%0 is not marked @objc dynamic" - -- id: dynamic_replacement_replacement_not_objc_dynamic - msg: "%0 is marked @objc dynamic" - -- id: dynamic_replacement_replaced_constructor_is_convenience - msg: "replaced constructor %0 is marked as convenience" - -- id: dynamic_replacement_replaced_constructor_is_not_convenience - msg: "replaced constructor %0 is not marked as convenience" - -- id: non_nominal_type_eraser - msg: "type eraser must be a class, struct, or enum" - -- id: type_eraser_does_not_conform - msg: "type eraser %0 must conform to protocol %1" - -- id: type_eraser_not_accessible - msg: "%select{private|fileprivate|internal|public|open}0 type eraser %1 cannot have more restrictive access than protocol %2 (which is %select{private|fileprivate|internal|public|open}3)" - -- id: type_eraser_missing_init - msg: "type eraser %0 must have an initializer of the form 'init(erasing: T)'" - -- id: type_eraser_unviable_init - msg: "type eraser %0 has no viable initializer of the form 'init(erasing: T)'" - -- id: type_eraser_declared_here - msg: "type eraser declared here" - -- id: type_eraser_failable_init - msg: "'init(erasing:)' cannot be failable" - -- id: type_eraser_init_unsatisfied_requirements - msg: "'init(erasing:)' cannot have unsatisfied requirements when %0 = 'some %1'" - -- id: type_eraser_init_not_accessible - msg: "%select{private|fileprivate|internal|public|open}0 'init(erasing:)' cannot have more restrictive access than protocol %1 (which is %select{private|fileprivate|internal|public|open}2)" - -- id: availability_decl_unavailable - msg: "%select{getter for |setter for |}0%1 is unavailable%select{ in %3|}2%select{|: %4}4" - -- id: availability_decl_unavailable_warn - msg: "%select{getter for |setter for |}0%1 is unavailable%select{ in %3|}2%select{|: %4}4" - -- id: availability_decl_unavailable_rename - msg: "%select{getter for |setter for |}0%1 has been %select{renamed to|replaced by}2%select{| instance method| property}3 '%4'%select{|: %5}5" - -- id: availability_decl_unavailable_rename_warn - msg: "%select{getter for |setter for |}0%1 has been %select{renamed to|replaced by}2%select{| instance method| property}3 '%4'%select{|: %5}5" - -- id: availability_marked_unavailable - msg: "%select{getter for |setter for |}0%1 has been explicitly marked unavailable here" - -- id: availability_introduced_in_version - msg: "%select{getter for |setter for |}0%1 was introduced in %2 %3" - -- id: availability_obsoleted - msg: "%select{getter for |setter for |}0%1 was obsoleted in %2 %3" - -- id: availability_deprecated - msg: "%select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 deprecated%select{| in %3%select{| %5}4}2%select{|: %6}6" - -- id: availability_deprecated_rename - msg: "%select{getter for |setter for |}0%1 %select{is|%select{is|was}4}2 deprecated%select{| in %3%select{| %5}4}2: %select{renamed to|replaced by}6%select{| instance method| property}7 '%8'" - -- id: note_deprecated_rename - msg: "use '%0' instead" - -- id: availability_decl_more_than_enclosing - msg: "declaration cannot be more available than enclosing scope" - -- id: availability_decl_more_than_enclosing_enclosing_here - msg: "enclosing scope here" - -- id: availability_decl_only_version_newer - msg: "%0 is only available in %1 %2 or newer" - -- id: availability_opaque_types_only_version_newer - msg: "'some' return types are only available in %0 %1 or newer" - -- id: availability_guard_with_version_check - msg: "add 'if #available' version check" - -- id: availability_add_attribute - msg: "add @available attribute to enclosing %0" - -- id: availability_accessor_only_version_newer - msg: "%select{getter|setter}0 for %1 is only available in %2 %3 or newer" - -- id: availability_inout_accessor_only_version_newer - msg: "cannot pass as inout because %select{getter|setter}0 for %1 is only available in %2 %3 or newer" - -- id: availability_query_required_for_platform - msg: "condition required for target platform '%0'" - -- id: availability_query_useless_enclosing_scope - msg: "unnecessary check for '%0'; enclosing scope ensures guard will always be true" - -- id: availability_query_useless_enclosing_scope_here - msg: "enclosing scope here" - -- id: availability_global_script_no_potential - msg: "global variable cannot be marked potentially unavailable with '@available' in script mode" - -- id: availability_stored_property_no_potential - msg: "stored properties cannot be marked potentially unavailable with '@available'" - -- id: availability_protocol_requires_version - msg: "protocol %0 requires %1 to be available in %2 %3 and newer" - -- id: availability_protocol_requirement_here - msg: "protocol requirement here" - -- id: public_decl_needs_availability - msg: "public declarations should have an availability attribute when building with -require-explicit-availability" - -- id: availabilty_string_subscript_migration - msg: "subscripts returning String were obsoleted in Swift 4; explicitly construct a String from subscripted result" - -- id: discardable_result_on_void_never_function - msg: "@discardableResult declared on a function returning %select{Never|Void}0 is unnecessary" - -- id: fixed_layout_attr_on_internal_type - msg: "'@_fixed_layout' attribute can only be applied to '@usableFromInline' or public declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1" - -- id: fixed_layout_struct - msg: "'@frozen' attribute is now used for fixed-layout structs" - -- id: frozen_attr_on_internal_type - msg: "'@frozen' attribute can only be applied to '@usableFromInline' or public declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1" - -- id: usable_from_inline_attr_with_explicit_access - msg: "'@usableFromInline' attribute can only be applied to internal declarations, but %0 is %select{private|fileprivate|%error|public|open}1" - -- id: inlinable_implies_usable_from_inline - msg: "'@inlinable' declaration is already '@usableFromInline'" - -- id: usable_from_inline_attr_in_protocol - msg: "'@usableFromInline' attribute cannot be used in protocols" - -- id: local_type_in_inlinable_function - msg: "type %0 cannot be nested inside %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}1" - -- id: resilience_decl_unavailable - msg: "%select{%0|%0 for}4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and cannot be referenced from %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}3" - -- id: resilience_decl_unavailable_warn - msg: "%select{%0|%0 for}4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and should not be referenced from %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}3" - -- id: inlinable_decl_ref_from_hidden_module - msg: "%0 %1 cannot be used in %select{a '@_transparent' function|an '@inlinable' function|an '@_alwaysEmitIntoClient' function|a default argument value|a property initializer in a '@frozen' type}2 because %select{%3 was imported implementation-only|it is an SPI imported from %3|it is SPI}4" - -- id: resilience_decl_declared_here_public - msg: "%select{%0|%0 for}2 %1 is not public" - -- id: resilience_decl_declared_here - msg: "%select{%0|%0 for}2 %1 is not '@usableFromInline' or public" - -- id: class_designated_init_inlinable_resilient - msg: "initializer for class %0 is '%select{@_transparent|@inlinable|@_alwaysEmitIntoClient|%error}1' and must delegate to another initializer" - -- id: attribute_invalid_on_stored_property - msg: "'%0' attribute cannot be applied to stored properties" - -- id: inlinable_dynamic_not_supported - msg: "'@inlinable' attribute cannot be applied to 'dynamic' declarations" - -- id: inlinable_decl_not_public - msg: "'@inlinable' attribute can only be applied to public declarations, but %0 is %select{private|fileprivate|internal|%error|%error}1" - -- id: inlinable_resilient_deinit - msg: "deinitializer can only be '@inlinable' if the class is '@_fixed_layout'" - -- id: specialize_attr_nongeneric_trailing_where - msg: "trailing 'where' clause in '_specialize' attribute of non-generic function %0" - -- id: specialize_missing_where_clause - msg: "missing 'where' clause in '_specialize' attribute" - -- id: specialize_empty_where_clause - msg: "empty 'where' clause in '_specialize' attribute" - -- id: specialize_attr_non_concrete_same_type_req - msg: "Only concrete type same-type requirements are supported by '_specialize' attribute" - -- id: specialize_attr_only_generic_param_req - msg: "Only requirements on generic parameters are supported by '_specialize' attribute" - -- id: specialize_attr_only_one_concrete_same_type_req - msg: "Only one concrete type should be used in the same-type requirement in '_specialize' attribute" - -- id: specialize_attr_non_protocol_type_constraint_req - msg: "Only conformances to protocol types are supported by '_specialize' attribute" - -- id: specialize_attr_type_parameter_count_mismatch - msg: "%select{too many|too few}2 type parameters are specified in '_specialize' attribute (got %1, but expected %0)" - -- id: specialize_attr_missing_constraint - msg: "Missing constraint for %0 in '_specialize' attribute" - -- id: specialize_attr_unsupported_kind_of_req - msg: "Only same-type and layout requirements are supported by '_specialize' attribute" - -- id: pbd_never_used_stmtcond - msg: "value %0 was defined but never used; consider replacing with boolean test" - -- id: unused_setter_parameter - msg: "setter argument %0 was never used, but the property was accessed" - -- id: fixit_for_unused_setter_parameter - msg: "did you mean to use %0 instead of accessing the property's current value?" - -- id: pbd_never_used - msg: "initialization of %select{variable|immutable value}1 %0 was never used; consider replacing with assignment to '_' or removing it" - -- id: capture_never_used - msg: "capture %0 was never used" - -- id: variable_never_used - msg: "%select{variable|immutable value}1 %0 was never used; consider replacing with '_' or removing it" - -- id: immutable_value_never_used_but_assigned - msg: "immutable value %0 was never used; consider removing it" - -- id: variable_never_mutated - msg: "variable %0 was never mutated; consider %select{removing 'var' to make it|changing to 'let'}1 constant" - -- id: variable_never_read - msg: "variable %0 was written to, but never read" - -- id: observe_keypath_property_not_objc_dynamic - msg: "passing reference to non-'@objc dynamic' property %0 to KVO method %1 may lead to unexpected behavior or runtime trap" - -- id: default_magic_identifier_mismatch - msg: "parameter %0 with default argument '%1' passed to parameter %2, whose default argument is '%3'" - -- id: change_caller_default_to_match_callee - msg: "did you mean for parameter %0 to default to '%1'?" - -- id: silence_default_magic_identifier_mismatch - msg: "add parentheses to silence this warning" - -- id: debug_long_function_body - msg: "%0 %1 took %2ms to type-check (limit: %3ms)" - -- id: debug_long_closure_body - msg: "closure took %0ms to type-check (limit: %1ms)" - -- id: debug_long_expression - msg: "expression took %0ms to type-check (limit: %1ms)" - -- id: empty_switch_stmt - msg: "'switch' statement body must have at least one 'case' or 'default' block; do you want to add a default case?" - -- id: non_exhaustive_switch - msg: "switch must be exhaustive" - -- id: possibly_non_exhaustive_switch - msg: "the compiler is unable to check that this switch is exhaustive in reasonable time" - -- id: missing_several_cases - msg: "do you want to add %select{missing cases|a default clause}0?" - -- id: missing_unknown_case - msg: "handle unknown values using \"@unknown default\"" - -- id: non_exhaustive_switch_drop_unknown - msg: "remove '@unknown' to handle remaining values" - -- id: missing_particular_case - msg: "add missing case: '%0'" - -- id: redundant_particular_case - msg: "case is already handled by previous patterns; consider removing it" - -- id: redundant_particular_literal_case - msg: "literal value is already handled by previous pattern; consider removing it" - -- id: redundant_particular_literal_case_here - msg: "first occurrence of identical literal pattern is here" - -- id: non_exhaustive_switch_warn - msg: "switch must be exhaustive" - -- id: non_exhaustive_switch_unknown_only - msg: "switch covers known cases, but %0 may have additional unknown values%select{|, possibly added in future versions}1" - -- id: override_nsobject_hashvalue_error - msg: "'NSObject.hashValue' is not overridable; did you mean to override 'NSObject.hash'?" - -- id: hashvalue_implementation - msg: "'Hashable.hashValue' is deprecated as a protocol requirement; conform type %0 to 'Hashable' by implementing 'hash(into:)' instead" - -- id: property_wrapper_no_value_property - msg: "property wrapper type %0 does not contain a non-static property named %1" - -- id: property_wrapper_ambiguous_value_property - msg: "property wrapper type %0 has multiple non-static properties named %1" - -- id: property_wrapper_wrong_initial_value_init - msg: "%0 parameter type (%1) must be the same as its 'wrappedValue' property type (%2) or an @autoclosure thereof" - -- id: property_wrapper_failable_init - msg: "property wrapper initializer %0 cannot be failable" - -- id: property_wrapper_type_requirement_not_accessible - msg: "%select{private|fileprivate|internal|public|open}0 %1 %2 cannot have more restrictive access than its enclosing property wrapper type %3 (which is %select{private|fileprivate|internal|public|open}4)" - -- id: property_wrapper_ambiguous_enclosing_self_subscript - msg: "property wrapper type %0 has multiple enclosing-self subscripts %1" - -- id: property_wrapper_dynamic_self_type - msg: "property wrapper %select{wrapped value|projected value}0 cannot have dynamic Self type" - -- id: property_wrapper_attribute_not_on_property - msg: "property wrapper attribute %0 can only be applied to a property" - -- id: property_wrapper_declared_here - msg: "property wrapper type %0 declared here" - -- id: property_wrapper_mutating_get_composed_to_get_only - msg: "property wrapper %0 with a mutating getter cannot be composed inside get-only property wrapper %1" - -- id: property_wrapper_local - msg: "property wrappers are not yet supported on local properties" - -- id: property_wrapper_top_level - msg: "property wrappers are not yet supported in top-level code" - -- id: property_wrapper_let - msg: "property wrapper can only be applied to a 'var'" - -- id: property_wrapper_computed - msg: "property wrapper cannot be applied to a computed property" - -- id: property_with_wrapper_conflict_attribute - msg: "property %0 with a wrapper cannot also be %select{lazy|@NSCopying|@NSManaged|weak|unowned|unmanaged}1" - -- id: property_wrapper_not_single_var - msg: "property wrapper can only apply to a single variable" - -- id: property_with_wrapper_in_bad_context - msg: "%select{|non-static |non-static }1property %0 declared inside %select{a protocol|an extension|an enum}1 cannot have a wrapper" - -- id: property_with_wrapper_overrides - msg: "property %0 with attached wrapper cannot override another property" - -- id: property_wrapper_direct_init - msg: "initialize the property wrapper type directly with '(...') on the attribute" - -- id: property_wrapper_incompatible_property - msg: "property type %0 does not match that of the 'wrappedValue' property of its wrapper type %1" - -- id: wrapped_value_mismatch - msg: "property type %0 does not match 'wrappedValue' type %1" - -- id: composed_property_wrapper_mismatch - msg: "composed wrapper type %0 does not match former 'wrappedValue' type %1" - -- id: property_wrapper_type_access - msg: "%select{%select{variable|constant}0|property}1 %select{must be declared %select{%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4|cannot be declared %select{in this context|fileprivate|internal|public|open}3}2 because its property wrapper type uses %select{a private|a fileprivate|an internal|%error|%error}5 type" - -- id: property_wrapper_type_not_usable_from_inline - msg: "property wrapper type referenced from a '@usableFromInline' %select{%select{variable|constant}0|property}1 must be '@usableFromInline' or public" - -- id: property_wrapper_wrapperValue - msg: "property wrapper's 'wrapperValue' property should be renamed to 'projectedValue'; use of 'wrapperValue' is deprecated" - -- id: property_wrapper_init_initialValue - msg: "property wrapper's 'init(initialValue:)' should be renamed to 'init(wrappedValue:)'; use of 'init(initialValue:)' is deprecated" - -- id: property_wrapper_projection_value_missing - msg: "could not find projection value property %0" - -- id: property_wrapper_missing_arg_init - msg: "missing argument for parameter %0 in property wrapper initializer; add 'wrappedValue' and %0 arguments in '@%1(...)'" - -- id: function_builder_decl - msg: "closure containing a declaration cannot be used with function builder %0" - -- id: note_function_builder_decl - msg: "closure containing a declaration cannot be used with function builder %0" - -- id: function_builder_control_flow - msg: "closure containing control flow statement cannot be used with function builder %0" - -- id: note_function_builder_control_flow - msg: "closure containing control flow statement cannot be used with function builder %0" - -- id: function_builder_attribute_not_allowed_here - msg: "function builder attribute %0 can only be applied to a parameter, function, or computed property" - -- id: function_builder_attribute_on_storage_without_getter - msg: "function builder attribute %0 can only be applied to a %select{subscript|property|constant|variable}1 if it defines a getter" - -- id: function_builder_parameter_not_of_function_type - msg: "function builder attribute %0 can only be applied to a parameter of function type" - -- id: function_builder_parameter_autoclosure - msg: "function builder attribute %0 cannot be applied to an autoclosure parameter" - -- id: function_builder_multiple - msg: "only one function builder attribute can be attached to a %select{declaration|parameter}0" - -- id: previous_function_builder_here - msg: "previous function builder specified here" - -- id: function_builder_arguments - msg: "function builder attributes cannot have arguments" - -- id: function_builder_disabled_by_return - msg: "application of function builder %0 disabled by explicit 'return' statement" - -- id: function_builder_remove_attr - msg: "remove the attribute to explicitly disable the function builder" - -- id: function_builder_remove_returns - msg: "remove 'return' statements to apply the function builder" - -- id: function_builder_infer_ambig - msg: "ambiguous function builder inferred for %0: %1 or %2" - -- id: function_builder_infer_add_return - msg: "add an explicit 'return' statement to not use a function builder" - -- id: function_builder_infer_pick_specific - msg: "apply function builder %0 (inferred from %select{protocol|dynamic replacement of}1 %2)" - -- id: function_builder_missing_limited_availability - msg: "function builder %0 does not implement 'buildLimitedAvailability'; this code may crash on earlier versions of the OS" - -- id: warn_reordering_tuple_shuffle_deprecated - msg: "expression shuffles the elements of this tuple; this behavior is deprecated" - -- id: differentiable_programming_attr_used_without_required_module - msg: "'@%0' attribute used without importing module %1" - -- id: oslog_arg_must_be_bool_literal - msg: "argument must be a bool literal" - -- id: oslog_arg_must_be_integer_literal - msg: "argument must be an integer literal" - -- id: oslog_arg_must_be_string_literal - msg: "argument must be a string literal" - -- id: oslog_arg_must_be_float_literal - msg: "argument must be a floating-point literal" - -- id: oslog_arg_must_be_metatype_literal - msg: "argument must be a .self" - -- id: oslog_arg_must_be_closure - msg: "argument must be a closure" - -- id: argument_must_be_constant - msg: "argument must be an expression with only literals" - -- id: oslog_message_must_be_string_interpolation - msg: "argument must be a string interpolation" - -- id: oslog_arg_must_be_enum_case - msg: "argument must be a case of enum %0" - -- id: oslog_arg_must_be_type_member_access - msg: "argument must be a static method or property of %0" - -- id: atomics_ordering_must_be_constant - msg: "ordering argument must be a static method or property of %0" - -- id: warning_from_clang - msg: "%0" - -- id: error_from_clang - msg: "%0" - -- id: note_from_clang - msg: "%0" - -- id: remark_from_clang - msg: "%0" - -- id: clang_cannot_build_module - msg: "could not build %select{C|Objective-C}0 module '%1'" - -- id: bridging_header_missing - msg: "bridging header '%0' does not exist" - -- id: bridging_header_error - msg: "failed to import bridging header '%0'" - -- id: could_not_rewrite_bridging_header - msg: "failed to serialize bridging header; target may not be debuggable outside of its original project" - -- id: bridging_header_pch_error - msg: "failed to emit precompiled header '%0' for bridging header '%1'" - -- id: emit_pcm_error - msg: "failed to emit precompiled module '%0' for module map '%1'" - -- id: dump_pcm_error - msg: "failed to dump precompiled module '%0'" - -- id: invalid_swift_name_method - msg: "too %select{few|many}0 parameters in swift_name attribute (expected %1; got %2)" - -- id: note_while_importing - msg: "while importing '%0'" - -- id: swift_name_protocol_static - msg: "swift_name cannot be used to define %select{static member|init}0 on protocol" - -- id: swift_name_no_prototype - msg: "swift_name cannot be used on a non-prototyped function declaration" - -- id: inconsistent_swift_name - msg: "inconsistent Swift name for Objective-C %select{method|property}0 '%1' in '%2' (%3 in '%4' vs. %5 in '%6')" - -- id: unresolvable_clang_decl - msg: "imported declaration '%0' could not be mapped to '%1'" - -- id: unresolvable_clang_decl_is_a_framework_bug - msg: "please report this issue to the owners of '%0'" - -- id: implicit_bridging_header_imported_from_module - msg: "implicit import of bridging header '%0' via module %1 is deprecated and will be removed in a later version of Swift" - -- id: bridging_module_missing - msg: "unable to find module '%0' for implicit conversion function '%0.%1'" - -- id: bridging_function_missing - msg: "unable to find implicit conversion function '%0.%1'" - -- id: bridging_function_overloaded - msg: "multiple definitions of implicit conversion function '%0.%1'" - -- id: bridging_function_not_function - msg: "definition of implicit conversion function '%0.%1' is not a function" - -- id: bridging_function_not_correct_type - msg: "definition of implicit conversion function '%0.%1' is not of the correct type" - -- id: bridging_objcbridgeable_missing - msg: "cannot find definition of '_ObjectiveCBridgeable' protocol" - -- id: bridging_objcbridgeable_broken - msg: "broken definition of '_ObjectiveCBridgeable' protocol: missing %0" - -- id: invalid_sil_builtin - msg: "INTERNAL ERROR: invalid use of builtin: %0" - -- id: could_not_find_bridge_type - msg: "could not find Objective-C bridge type for type %0; did you forget to import Foundation?" - -- id: could_not_find_pointer_pointee_property - msg: "could not find 'pointee' property of pointer type %0" - -- id: writeback_overlap_property - msg: "inout writeback to computed property %0 occurs in multiple arguments to call, introducing invalid aliasing" - -- id: writeback_overlap_subscript - msg: "inout writeback through subscript occurs in multiple arguments to call, introducing invalid aliasing" - -- id: writebackoverlap_note - msg: "concurrent writeback occurred here" - -- id: inout_argument_alias - msg: "inout arguments are not allowed to alias each other" - -- id: previous_inout_alias - msg: "previous aliasing argument" - -- id: unimplemented_generator_witnesses - msg: "protocol conformance emission for generator coroutines is unimplemented" - -- id: exclusivity_access_required - msg: "overlapping accesses to %0, but %select{initialization|read|modification|deinitialization}1 requires exclusive access; %select{consider copying to a local variable|consider calling MutableCollection.swapAt(_:_:)}2" - -- id: exclusivity_access_required_unknown_decl - msg: "overlapping accesses, but %select{initialization|read|modification|deinitialization}0 requires exclusive access; consider copying to a local variable" - -- id: exclusivity_conflicting_access - msg: "conflicting access is here" - -- id: unsupported_c_function_pointer_conversion - msg: "C function pointer signature %0 is not compatible with expected type %1" - -- id: c_function_pointer_from_function_with_context - msg: "a C function pointer cannot be formed from a %select{local function|closure}0 that captures %select{context|generic parameters|dynamic Self type}1" - -- id: objc_selector_malformed - msg: "the type ObjectiveC.Selector is malformed" - -- id: capture_before_declaration - msg: "closure captures %0 before it is declared" - -- id: capture_before_declaration_defer - msg: "'defer' block captures %0 before it is declared" - -- id: captured_value_declared_here - msg: "captured value declared here" - -- id: escaping_inout_capture - msg: "escaping %select{local function|closure|autoclosure}0 captures 'inout' parameter %1" - -- id: inout_param_defined_here - msg: "parameter %0 is declared 'inout'" - -- id: escaping_mutable_self_capture - msg: "escaping %select{local function|closure|autoclosure}0 captures mutating 'self' parameter" - -- id: escaping_noescape_param_capture - msg: "escaping %select{local function|closure|autoclosure}0 captures non-escaping parameter %1" - -- id: noescape_param_defined_here - msg: "parameter %0 is implicitly non-escaping" - -- id: escaping_noescape_var_capture - msg: "escaping %select{local function|closure|autoclosure}0 captures non-escaping value" - -- id: value_captured_here - msg: "captured here" - -- id: copy_inout_captured_by_autoclosure - msg: "pass a copy of %0" - -- id: copy_self_captured_by_autoclosure - msg: "pass a copy of 'self'" - -- id: value_captured_transitively - msg: "captured indirectly by this call" - -- id: err_noescape_param_call - msg: "passing a %select{|closure which captures a }1non-escaping function parameter %0 to a call to a non-escaping function parameter can allow re-entrant modification of a variable" - -- id: variable_defined_here - msg: "%select{variable|constant}0 defined here" - -- id: variable_used_before_initialized - msg: "%select{variable|constant}1 '%0' used before being initialized" - -- id: variable_inout_before_initialized - msg: "%select{variable|constant}1 '%0' passed by reference before being initialized" - -- id: variable_closure_use_uninit - msg: "%select{variable|constant}1 '%0' captured by a closure before being initialized" - -- id: variable_defer_use_uninit - msg: "%select{variable|constant}1 '%0' used in defer before being initialized" - -- id: self_closure_use_uninit - msg: "'self' captured by a closure before all members were initialized" - -- id: variable_addrtaken_before_initialized - msg: "address of %select{variable|constant}1 '%0' taken before it is initialized" - -- id: ivar_not_initialized_at_superinit - msg: "property '%0' not initialized at super.init call" - -- id: ivar_not_initialized_at_implicit_superinit - msg: "property '%0' not initialized at implicitly generated super.init call" - -- id: self_use_before_fully_init - msg: "'self' used in %select{method call|property access}1 %0 before %select{all stored properties are initialized|'super.init' call|'self.init' call}2" - -- id: use_of_self_before_fully_init - msg: "'self' used before all stored properties are initialized" - -- id: stored_property_not_initialized - msg: "'%0' not initialized" - -- id: selfinit_multiple_times - msg: "'%select{super|self}0.init' called multiple times in initializer" - -- id: superselfinit_not_called_before_return - msg: "'%select{super|self}0.init' isn't called on all paths before returning from initializer" - -- id: self_before_superinit - msg: "'self' used before 'super.init' call" - -- id: self_before_selfinit - msg: "'self' used before 'self.init' call" - -- id: self_before_selfinit_value_type - msg: "'self' used before 'self.init' call or assignment to 'self'" - -- id: self_inside_catch_superselfinit - msg: "'self' used inside 'catch' block reachable from %select{super|self}0.init call" - -- id: return_from_init_without_initing_stored_properties - msg: "return from initializer without initializing all stored properties" - -- id: variable_function_use_uninit - msg: "%select{variable|constant}1 '%0' used by function definition before being initialized" - -- id: struct_not_fully_initialized - msg: "struct '%0' must be completely initialized before a member is stored to" - -- id: immutable_property_already_initialized - msg: "immutable value '%0' may only be initialized once" - -- id: initial_value_provided_in_let_decl - msg: "initial value already provided in 'let' declaration" - -- id: mutation_of_property_of_immutable_value - msg: "cannot mutate %select{property %0|subscript}1 of immutable value '%2'" - -- id: using_mutating_accessor_on_immutable_value - msg: "mutating accessor for %select{property %0|subscript}1 may not be used on immutable value '%2'" - -- id: mutating_method_called_on_immutable_value - msg: "mutating %select{method|operator}1 %0 may not be used on immutable value '%2'" - -- id: immutable_value_passed_inout - msg: "immutable value '%0' must not be passed inout" - -- id: assignment_to_immutable_value - msg: "immutable value '%0' must not be assigned to" - -- id: designated_init_in_cross_module_extension - msg: "initializer for struct %0 must use \"self.init(...)\" or \"self = ...\"%select{| on all paths}1 because %select{it is not in module %2|the struct was imported from C}3" - -- id: designated_init_c_struct_fix - msg: "use \"self.init()\" to initialize the struct with zero values" - -- id: missing_return - msg: "missing return in a %select{function|closure}1 expected to return %0" - -- id: missing_return_last_expr - msg: "missing return in a %select{function|closure}1 expected to return %0; did you mean to return the last expression?" - -- id: missing_never_call - msg: "%select{function|closure}1 with uninhabited return type %0 is missing call to another never-returning function on all paths" - -- id: guard_body_must_not_fallthrough - msg: "'guard' body must not fall through, consider using a 'return' or 'throw' to exit the scope" - -- id: unreachable_code - msg: "will never be executed" - -- id: unreachable_code_uninhabited_param_note - msg: "'%0' is uninhabited, so this function body can never be executed" - -- id: unreachable_code_branch - msg: "condition always evaluates to %select{false|true}0" - -- id: call_to_noreturn_note - msg: "a call to a never-returning function" - -- id: unreachable_code_after_stmt - msg: "code after '%select{return|break|continue|throw}0' will never be executed" - -- id: unreachable_case - msg: "%select{case|default}0 will never be executed" - -- id: switch_on_a_constant - msg: "switch condition evaluates to a constant" - -- id: unreachable_code_note - msg: "will never be executed" - -- id: warn_infinite_recursive_function - msg: "all paths through this function will call itself" - -- id: circular_transparent - msg: "inlining 'transparent' functions forms circular loop" - -- id: note_while_inlining - msg: "while inlining here" - -- id: cannot_prespecialize - msg: "Cannot pre-specialize %0" - -- id: missing_prespecialization - msg: "Pre-specialized function %0 missing in SwiftOnoneSupport module" - -- id: integer_conversion_overflow - msg: "integer overflows when converted from %0 to %1" - -- id: integer_conversion_overflow_builtin_types - msg: "integer overflows when converted from %select{unsigned|signed}0 %1 to %select{unsigned|signed}2 %3" - -- id: integer_conversion_overflow_warn - msg: "integer overflows when converted from %0 to %1" - -- id: negative_integer_literal_overflow_unsigned - msg: "negative integer '%1' overflows when stored into unsigned type %0" - -- id: integer_literal_overflow - msg: "integer literal '%1' overflows when stored into %0" - -- id: integer_literal_overflow_builtin_types - msg: "integer literal '%2' overflows when stored into %select{unsigned|signed}0 %1" - -- id: integer_literal_overflow_warn - msg: "integer literal overflows when stored into %0" - -- id: arithmetic_operation_overflow - msg: "arithmetic operation '%0 %1 %2' (on type %3) results in an overflow" - -- id: arithmetic_operation_overflow_generic_type - msg: "arithmetic operation '%0 %1 %2' (on %select{unsigned|signed}3 %4-bit integer type) results in an overflow" - -- id: division_overflow - msg: "division '%0 %1 %2' results in an overflow" - -- id: division_by_zero - msg: "division by zero" - -- id: wrong_non_negative_assumption - msg: "assumed non-negative value '%0' is negative" - -- id: shifting_all_significant_bits - msg: "shift amount is greater than or equal to type size in bits" - -- id: static_report_error - msg: "static report error" - -- id: pound_assert_condition_not_constant - msg: "#assert condition not constant" - -- id: pound_assert_failure - msg: "%0" - -- id: constexpr_unknown_reason_default - msg: "cannot evaluate expression as constant here" - -- id: constexpr_unevaluable_operation - msg: "cannot constant evaluate operation%select{| used by this call}0" - -- id: constexpr_too_many_instructions - msg: "exceeded instruction limit: %0 when evaluating the expression at compile time" - -- id: constexpr_limit_exceeding_instruction - msg: "limit exceeded %select{here|during this call}0" - -- id: constexpr_loop_found_note - msg: "control-flow loop found during evaluation " - -- id: constexpr_loop_instruction - msg: "found loop %select{here|inside this call}0" - -- id: constexpr_overflow - msg: "integer overflow detected" - -- id: constexpr_overflow_operation - msg: "operation%select{| performed during this call}0 overflows" - -- id: constexpr_trap - msg: "%0" - -- id: constexpr_trap_operation - msg: "operation%select{| performed during this call}0 traps" - -- id: constexpr_invalid_operand_seen - msg: "operation with invalid operands encountered during evaluation" - -- id: constexpr_operand_invalid_here - msg: "operation with invalid operands encountered %select{here|during this call}0" - -- id: constexpr_value_unknown_at_top_level - msg: "cannot evaluate top-level value as constant here" - -- id: constexpr_multiple_writers_found_at_top_level - msg: "top-level value has multiple assignments" - -- id: constexpr_unsupported_instruction_found - msg: "encountered operation not supported by the evaluator: %0" - -- id: constexpr_unsupported_instruction_found_here - msg: "operation%select{| used by this call is}0 not supported by the evaluator" - -- id: constexpr_found_callee_with_no_body - msg: "encountered call to '%0' whose body is not available. Imported functions must be marked '@inlinable' to constant evaluate" - -- id: constexpr_callee_with_no_body - msg: "%select{|calls a }0function whose body is not available" - -- id: constexpr_found_call_with_unknown_arg - msg: "encountered call to '%0' where the %1 argument is not a constant" - -- id: constexpr_call_with_unknown_arg - msg: "%select{|makes a }0function call with non-constant arguments" - -- id: constexpr_untracked_sil_value_use_found - msg: "encountered use of a variable not tracked by the evaluator" - -- id: constexpr_untracked_sil_value_used_here - msg: "untracked variable used %select{here|by this call}0" - -- id: constexpr_unevaluable_cast_found - msg: "encountered an unevaluable cast" - -- id: constexpr_unevaluable_cast_used_here - msg: "unevaluable cast encountered %select{here|by this call}0" - -- id: constexpr_unresolvable_witness_call - msg: "encountered unresolvable witness method call: '%0'" - -- id: constexpr_no_witness_table_entry - msg: "cannot find witness table entry %select{for this call|for a witness-method invoked during this call}0" - -- id: constexpr_witness_call_with_no_conformance - msg: "cannot find concrete conformance %select{for this call|for a witness-method invoked during this call}0" - -- id: constexpr_unknown_control_flow_due_to_skip - msg: "branch depends on non-constant value produced by an unevaluated instructions" - -- id: constexpr_returned_by_unevaluated_instruction - msg: "result of an unevaluated instruction is not a constant" - -- id: constexpr_mutated_by_unevaluated_instruction - msg: "value mutable by an unevaluated instruction is not a constant" - -- id: not_constant_evaluable - msg: "not constant evaluable" - -- id: constexpr_imported_func_not_onone - msg: "imported constant evaluable function '%0' must be annotated '@_optimize(none)'" - -- id: autodiff_internal_swift_not_imported - msg: "Automatic differentiation internal error: the Swift module is not imported" - -- id: autodiff_differentiation_module_not_imported - msg: "Automatic differentiation requires the '_Differentiation' module to be imported" - -- id: autodiff_conversion_to_linear_function_not_supported - msg: "conversion to '@differentiable(linear)' function type is not yet supported" - -- id: autodiff_function_not_differentiable_error - msg: "function is not differentiable" - -- id: autodiff_expression_not_differentiable_error - msg: "expression is not differentiable" - -- id: autodiff_expression_not_differentiable_note - msg: "expression is not differentiable" - -- id: autodiff_when_differentiating_function_call - msg: "when differentiating this function call" - -- id: autodiff_when_differentiating_function_definition - msg: "when differentiating this function definition" - -- id: autodiff_implicitly_inherited_differentiable_attr_here - msg: "differentiability required by the corresponding protocol requirement here" - -- id: autodiff_jvp_control_flow_not_supported - msg: "forward-mode differentiation does not yet support control flow" - -- id: autodiff_control_flow_not_supported - msg: "cannot differentiate unsupported control flow" - -- id: autodiff_missing_return - msg: "missing return for differentiation" - -- id: autodiff_external_nondifferentiable_function - msg: "cannot differentiate functions that have not been marked '@differentiable' and that are defined in other files" - -- id: autodiff_opaque_function_not_differentiable - msg: "opaque non-'@differentiable' function is not differentiable" - -- id: autodiff_private_derivative_from_fragile - msg: "differentiated functions in %select{'@inlinable' functions|default arguments}0 must be marked '@differentiable' or have a public '@derivative'%select{|; this is not possible with a closure, make a top-level function instead}1" - -- id: autodiff_function_noderivative_parameter_not_differentiable - msg: "cannot differentiate with respect to a '@noDerivative' parameter" - -- id: autodiff_function_assoc_func_unmet_requirements - msg: "function call is not differentiable because generic requirements are not met: '%0'" - -- id: autodiff_nondifferentiable_argument - msg: "cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?" - -- id: autodiff_nondifferentiable_result - msg: "cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?" - -- id: autodiff_protocol_member_not_differentiable - msg: "member is not differentiable because the corresponding protocol requirement is not '@differentiable'" - -- id: autodiff_class_member_not_differentiable - msg: "member is not differentiable because the corresponding class member is not '@differentiable'" - -- id: autodiff_member_subset_indices_not_differentiable - msg: "member is differentiable only with respect to a smaller subset of arguments" - -- id: autodiff_cannot_param_subset_thunk_partially_applied_orig_fn - msg: "cannot convert a direct method reference to a '@differentiable' function; use an explicit closure instead" - -- id: autodiff_cannot_differentiate_through_multiple_results - msg: "cannot differentiate through multiple results" - -- id: autodiff_cannot_differentiate_through_inout_arguments - msg: "cannot differentiate through 'inout' arguments" - -- id: autodiff_enums_unsupported - msg: "differentiating enum values is not yet supported" - -- id: autodiff_stored_property_parent_not_differentiable - msg: "cannot differentiate access to property '%0.%1' because '%0' does not conform to 'Differentiable'" - -- id: autodiff_stored_property_not_differentiable - msg: "cannot differentiate access to property '%0.%1' because property type %2 does not conform to 'Differentiable'" - -- id: autodiff_stored_property_tangent_not_struct - msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector' is not a struct" - -- id: autodiff_stored_property_no_corresponding_tangent - msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector' does not have a stored property named '%1'" - -- id: autodiff_tangent_property_wrong_type - msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector.%1' does not have expected type %2" - -- id: autodiff_tangent_property_not_stored - msg: "cannot differentiate access to property '%0.%1' because '%0.TangentVector.%1' is not a stored property" - -- id: autodiff_coroutines_not_supported - msg: "differentiation of coroutine calls is not yet supported" - -- id: autodiff_cannot_differentiate_writes_to_global_variables - msg: "cannot differentiate writes to global variables" - -- id: autodiff_cannot_differentiate_writes_to_mutable_captures - msg: "cannot differentiate writes to mutable captures" - -- id: non_physical_addressof - msg: "addressof only works with purely physical lvalues; use 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing 'withUnsafePointer' or 'withUnsafeBytes'" - -- id: non_borrowed_indirect_addressof - msg: "addressof only works with borrowable in-memory rvalues; use 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing 'withUnsafePointer' or 'withUnsafeBytes'" - -- id: opt_remark_passed - msg: "%0" - -- id: opt_remark_missed - msg: "%0" - -- id: opt_remark_note - msg: "%0" - -- id: float_to_int_overflow - msg: "invalid%select{| implicit}2 conversion: '%0' overflows %1" - -- id: negative_fp_literal_overflow_unsigned - msg: "negative literal '%0' cannot be converted to %select{|unsigned }2%1" - -- id: warning_float_trunc_overflow - msg: "'%0' overflows to %select{|-}2inf during conversion to %1" - -- id: warning_float_trunc_underflow - msg: "'%0' underflows and loses precision during conversion to %1" - -- id: warning_float_trunc_hex_inexact - msg: "'%0' loses precision during conversion to %1" - -- id: warning_float_overflows_maxbuiltin - msg: "'%0' overflows to %select{|-}1inf because its magnitude exceeds the limits of a float literal" - -- id: warning_int_to_fp_inexact - msg: "'%1' is not exactly representable as %0; it becomes '%2'" - -- id: return_before_yield - msg: "accessor must yield before returning" - -- id: multiple_yields - msg: "accessor must not yield more than once" - -- id: previous_yield - msg: "previous yield was here" - -- id: possible_return_before_yield - msg: "accessor must yield on all paths before returning" - -- id: branch_doesnt_yield - msg: "missing yield when the condition is %select{false|true}0" - -- id: named_case_doesnt_yield - msg: "missing yield in the %0 case" - -- id: case_doesnt_yield - msg: "missing yield in %select{this|the nil|the non-nil}0 case" - -- id: switch_value_case_doesnt_yield - msg: "missing yield in the %0 case" - -- id: try_branch_doesnt_yield - msg: "missing yield when error is %select{not |}0thrown" - -- id: oslog_constant_eval_trap - msg: "%0" - -- id: oslog_too_many_instructions - msg: "interpolated expression and arguments are too complex" - -- id: oslog_invalid_log_message - msg: "invalid log message; extending types defined in the os module is not supported" - -- id: oslog_const_evaluable_fun_error - msg: "'%0' failed evaluation" - -- id: oslog_non_constant_message - msg: "'OSLogMessage' instance passed to the log call is not a constant" - -- id: oslog_non_constant_interpolation - msg: "'OSLogInterpolation' instance passed to 'OSLogMessage.init' is not a constant" - -- id: oslog_property_not_constant - msg: "'OSLogInterpolation.%0' is not a constant" - -- id: oslog_message_alive_after_opts - msg: "string interpolation cannot be used in this context; if you are calling an os_log function, try a different overload" - -- id: oslog_message_explicitly_created - msg: "'OSLogMessage' must be created from a string interpolation or string literal" - -- id: oslog_call_in_unreachable_code - msg: "os log call will never be executed and may have undiagnosed errors" - -- id: global_string_pointer_on_non_constant - msg: "globalStringTablePointer builtin must be used only on string literals" - -- id: polymorphic_builtin_passed_non_trivial_non_builtin_type - msg: "Argument of type %0 can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed" - -- id: polymorphic_builtin_passed_type_without_static_overload - msg: "Static overload %0 does not exist for polymorphic builtin '%1'. Static overload implied by passing argument of type %2" - -- id: box_to_stack_cannot_promote_box_to_stack_due_to_escape_alloc - msg: "Can not promote value from heap to stack due to value escaping" - -- id: box_to_stack_cannot_promote_box_to_stack_due_to_escape_location - msg: "value escapes here" - -- id: no_llvm_target - msg: "error loading LLVM target for triple '%0': %1" - -- id: error_codegen_init_fail - msg: "cannot initialize code generation passes for target" - -- id: irgen_unimplemented - msg: "unimplemented IR generation feature %0" - -- id: irgen_failure - msg: "IR generation failure: %0" - -- id: type_to_verify_not_found - msg: "unable to find type '%0' to verify" - -- id: type_to_verify_ambiguous - msg: "type to verify '%0' is ambiguous" - -- id: type_to_verify_dependent - msg: "type to verify '%0' has unbound generic parameters" - -- id: too_few_output_filenames - msg: "too few output file names specified" - -- id: no_input_files_for_mt - msg: "no swift input files for multi-threaded compilation" - -- id: alignment_dynamic_type_layout_unsupported - msg: "@_alignment is not supported on types with dynamic layout" - -- id: alignment_less_than_natural - msg: "@_alignment cannot decrease alignment below natural alignment of %0" - -- id: alignment_more_than_maximum - msg: "@_alignment cannot increase alignment above maximum alignment of %0" - -- id: warning_no_such_sdk - msg: "no such SDK: '%0'" - -- id: error_no_frontend_args - msg: "no arguments provided to '-frontend'" - -- id: error_no_such_file_or_directory - msg: "no such file or directory: '%0'" - -- id: error_unsupported_target_os - msg: "unsupported target OS: '%0'" - -- id: error_unsupported_target_arch - msg: "unsupported target architecture: '%0'" - -- id: error_unsupported_opt_for_target - msg: "unsupported option '%0' for target '%1'" - -- id: warning_inferred_simulator_target - msg: "inferring simulator environment for target '%0'; use '-target %1' instead" - -- id: error_argument_not_allowed_with - msg: "argument '%0' is not allowed with '%1'" - -- id: warning_argument_not_supported_with_optimization - msg: "argument '%0' is not supported with optimization" - -- id: error_option_requires_sanitizer - msg: "option '%0' requires a sanitizer to be enabled. Use -sanitize= to enable a sanitizer" - -- id: warning_option_requires_specific_sanitizer - msg: "option '%0' has no effect when '%1' sanitizer is disabled. Use -sanitize=%1 to enable the sanitizer" - -- id: error_option_missing_required_argument - msg: "option '%0' is missing a required argument (%1)" - -- id: cannot_open_file - msg: "cannot open file '%0' (%1)" - -- id: cannot_open_serialized_file - msg: "cannot open file '%0' for diagnostics emission (%1)" - -- id: error_open_input_file - msg: "error opening input file '%0' (%1)" - -- id: error_clang_importer_create_fail - msg: "clang importer creation failed" - -- id: error_missing_arg_value - msg: "missing argument value for '%0', expected %1 argument(s)" - -- id: error_unknown_arg - msg: "unknown argument: '%0'" - -- id: error_invalid_arg_value - msg: "invalid value '%1' in '%0'" - -- id: warning_invalid_locale_code - msg: "unsupported locale code; supported locale codes are: '%0'" - -- id: warning_locale_path_not_found - msg: "specified localization directory '%0' does not exist, translation is disabled" - -- id: warning_cannot_find_locale_file - msg: "cannot find translations for '%0' at '%1': no such file" - -- id: warning_cannot_multithread_batch_mode - msg: "ignoring -num-threads argument; cannot multithread batch mode" - -- id: error_unsupported_option_argument - msg: "unsupported argument '%1' to option '%0'" - -- id: error_immediate_mode_missing_stdlib - msg: "could not load the swift standard library" - -- id: error_immediate_mode_missing_library - msg: "could not load %select{shared library|framework}0 '%1'" - -- id: error_immediate_mode_primary_file - msg: "immediate mode is incompatible with -primary-file" - -- id: error_missing_frontend_action - msg: "no frontend action was selected" - -- id: error_invalid_source_location_str - msg: "invalid source location string '%0'" - -- id: error_no_source_location_scope_map - msg: "-dump-scope-maps argument must be 'expanded' or a list of source locations" - -- id: note_valid_swift_versions - msg: "valid arguments to '-swift-version' are %0" - -- id: error_mode_cannot_emit_dependencies - msg: "this mode does not support emitting dependency files" - -- id: error_mode_cannot_emit_reference_dependencies - msg: "this mode does not support emitting reference dependency files" - -- id: error_mode_cannot_emit_swift_ranges - msg: "this mode does not support emitting unparsed ranges files" - -- id: error_mode_cannot_emit_compiled_source - msg: "this mode does not support emitting compiled source files" - -- id: error_mode_cannot_emit_header - msg: "this mode does not support emitting Objective-C headers" - -- id: error_mode_cannot_emit_loaded_module_trace - msg: "this mode does not support emitting the loaded module trace" - -- id: error_mode_cannot_emit_module - msg: "this mode does not support emitting modules" - -- id: error_mode_cannot_emit_module_doc - msg: "this mode does not support emitting module documentation files" - -- id: error_mode_cannot_emit_module_source_info - msg: "this mode does not support emitting module source info files" - -- id: error_mode_cannot_emit_interface - msg: "this mode does not support emitting module interface files" - -- id: cannot_emit_ir_skipping_function_bodies - msg: "-experimental-skip-non-inlinable-function-bodies does not support emitting IR" - -- id: emit_reference_dependencies_without_primary_file - msg: "ignoring -emit-reference-dependencies (requires -primary-file)" - -- id: emit_swift_ranges_without_primary_file - msg: "ignoring -emit-swift-ranges (requires -primary-file)" - -- id: emit_compiled_source_without_primary_file - msg: "ignoring -emit-compiled-source (requires -primary-file)" - -- id: error_bad_module_name - msg: "module name \"%0\" is not a valid identifier%select{|; use -module-name flag to specify an alternate name}1" - -- id: error_stdlib_module_name - msg: "module name \"%0\" is reserved for the standard library%select{|; use -module-name flag to specify an alternate name}1" - -- id: error_stdlib_not_found - msg: "unable to load standard library for target '%0'" - -- id: error_unable_to_load_supplementary_output_file_map - msg: "unable to load supplementary output file map '%0': %1" - -- id: error_missing_entry_in_supplementary_output_file_map - msg: "supplementary output file map '%0' is missing an entry for '%1' (this likely indicates a compiler issue; please file a bug report)" - -- id: error_repl_requires_no_input_files - msg: "REPL mode requires no input files" - -- id: error_mode_requires_one_input_file - msg: "this mode requires a single input file" - -- id: error_mode_requires_an_input_file - msg: "this mode requires at least one input file" - -- id: error_mode_requires_one_sil_multi_sib - msg: "this mode requires .sil for primary-file and only .sib for other inputs" - -- id: error_no_output_filename_specified - msg: "an output filename was not specified for a mode which requires an output filename" - -- id: error_implicit_output_file_is_directory - msg: "the implicit output file '%0' is a directory; explicitly specify a filename using -o" - -- id: error_if_any_output_files_are_specified_they_all_must_be - msg: "if any output files are specified, they all must be" - -- id: error_primary_file_not_found - msg: "primary file '%0' was not found in file list '%1'" - -- id: error_cannot_have_input_files_with_file_list - msg: "cannot have input files with file list" - -- id: error_cannot_have_primary_files_with_primary_file_list - msg: "cannot have primary input files with primary file list" - -- id: error_cannot_have_supplementary_outputs - msg: "cannot have '%0' with '%1'" - -- id: error_duplicate_input_file - msg: "duplicate input file '%0'" - -- id: repl_must_be_initialized - msg: "variables currently must have an initial value when entered at the top level of the REPL" - -- id: verify_encountered_fatal - msg: "fatal error encountered while in -verify mode" - -- id: error_parse_input_file - msg: "error parsing input file '%0' (%1)" - -- id: error_write_index_unit - msg: "writing index unit file: %0" - -- id: error_create_index_dir - msg: "creating index directory: %0" - -- id: error_write_index_record - msg: "writing index record file: %0" - -- id: error_index_failed_status_check - msg: "failed file status check: %0" - -- id: error_index_inputs_more_than_outputs - msg: "index output filenames do not match input source files" - -- id: error_wrong_number_of_arguments - msg: "wrong number of '%0' arguments (expected %1, got %2)" - -- id: error_formatting_multiple_file_ranges - msg: "file ranges don't support multiple input files" - -- id: error_formatting_invalid_range - msg: "file range is invalid" - -- id: stats_disabled - msg: "compiler was not built with support for collecting statistics" - -- id: tbd_warn_truncating_version - msg: "truncating %select{current|compatibility}0 version '%1' in TBD file to fit in 32-bit space used by old mach-o format" - -- id: tbd_err_invalid_version - msg: "invalid dynamic library %select{current|compatibility}0 version '%1'" - -- id: tbd_only_supported_in_whole_module - msg: "TBD generation is only supported when the whole module can be seen" - -- id: tbd_not_supported_with_cmo - msg: "Test-Based InstallAPI (TBD) is not support with cross-module-optimization" - -- id: linker_directives_choice_confusion - msg: "only one of -emit-ldadd-cfile-path and -module-installname-map-file can be specified;the c file won't be generated" - -- id: previous_installname_map_missing - msg: "cannot open previous install name map from %0" - -- id: previous_installname_map_corrupted - msg: "previous install name map from %0 is malformed" - -- id: explicit_swift_module_map_missing - msg: "cannot open explicit Swift module map from %0" - -- id: explicit_swift_module_map_corrupted - msg: "explicit Swift module map from %0 is malformed" - -- id: placeholder_dependency_module_map_missing - msg: "cannot open Swift placeholder dependency module map from %0" - -- id: placeholder_dependency_module_map_corrupted - msg: "Swift placeholder dependency module map from %0 is malformed" - -- id: default_previous_install_name - msg: "default previous install name for %0 is %1" - -- id: platform_previous_install_name - msg: "previous install name for %0 in %1 is %2" - -- id: unknown_platform_name - msg: "unkown platform name %0" - -- id: unknown_swift_module_name - msg: "cannot find Swift module with name %0" - -- id: cannot_find_install_name - msg: "cannot find previous install name for module %0 in %1" - -- id: symbol_in_tbd_not_in_ir - msg: "symbol '%0' (%1) is in TBD file, but not in generated IR" - -- id: symbol_in_ir_not_in_tbd - msg: "symbol '%0' (%1) is in generated IR file, but not in TBD file" - -- id: tbd_validation_failure - msg: "please file a radar or open a bug on bugs.swift.org with this code, and add -Xfrontend -validate-tbd-against-ir=none to squash the errors" - -- id: redundant_prefix_compilation_flag - msg: "invalid argument '-D%0'; did you provide a redundant '-D' in your build settings?" - -- id: invalid_conditional_compilation_flag - msg: "conditional compilation flags must be valid Swift identifiers (rather than '%0')" - -- id: cannot_assign_value_to_conditional_compilation_flag - msg: "conditional compilation flags do not have values in Swift; they are either present or absent (rather than '%0')" - -- id: framework_search_path_includes_framework_extension - msg: "framework search path ends in \".framework\"; add directory containing framework instead: %0" - -- id: error_optimization_remark_pattern - msg: "%0 in '%1'" - -- id: error_invalid_debug_prefix_map - msg: "invalid argument '%0' to -debug-prefix-map; it must be of the form 'original=remapped'" - -- id: error_invalid_coverage_prefix_map - msg: "invalid argument '%0' to -coverage-prefix-map; it must be of the form 'original=remapped'" - -- id: error_unable_to_write_swift_ranges_file - msg: "unable to write unparsed ranges file '$0': %1" - -- id: error_unable_to_write_compiled_source_file - msg: "unable to write compiled source file: '$0': %1" - -- id: invalid_vfs_overlay_file - msg: "invalid virtual overlay file '%0'" - -- id: module_interface_scoped_import_unsupported - msg: "scoped imports are not yet supported in module interfaces" - -- id: warn_unsupported_module_interface_swift_version - msg: "module interfaces are only supported with Swift language version 5 or later (currently using -swift-version %0)" - -- id: warn_unsupported_module_interface_library_evolution - msg: "module interfaces are only supported with -enable-library-evolution" - -- id: error_extracting_version_from_module_interface - msg: "error extracting version from module interface" - -- id: unsupported_version_of_module_interface - msg: "unsupported version of module interface '%0': '%1'" - -- id: error_opening_explicit_module_file - msg: "failed to open explicit Swift module: %0" - -- id: error_extracting_flags_from_module_interface - msg: "error extracting flags from module interface" - -- id: rebuilding_module_from_interface - msg: "rebuilding module '%0' from interface '%1'" - -- id: out_of_date_module_here - msg: "%select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1'" - -- id: module_interface_dependency_out_of_date - msg: "dependency is out of date: '%0'" - -- id: module_interface_dependency_missing - msg: "dependency is missing: '%0'" - -- id: compiled_module_invalid - msg: "unable to load compiled module '%0'" - -- id: compiled_module_invalid_reason - msg: "unable to load compiled module '%0': %1" - -- id: unknown_forced_module_loading_mode - msg: "unknown value for SWIFT_FORCE_MODULE_LOADING variable: '%0'" - -- id: error_creating_remark_serializer - msg: "error while creating remark serializer: '%0'" - -- id: interface_file_lock_failure - msg: "could not acquire lock file for module interface '%0'" - -- id: interface_file_lock_timed_out - msg: "timed out waiting to acquire lock file for module interface '%0'" - -- id: dependency_cascading_mismatch - msg: "expected %select{non-cascading|cascading}0 dependency; found %select{non-cascading|cascading}1 dependency instead" - -- id: potential_dependency_cascading_mismatch - msg: "expected %select{non-cascading|cascading}0 potential member dependency; found %select{non-cascading|cascading}1 potential member dependency instead" - -- id: missing_member_dependency - msg: "expected %select{%error|provided|member|potential member|dynamic member}0 dependency does not exist: %1" - -- id: unexpected_dependency - msg: "unexpected %0 %select{%error|%error|member|potential member|dynamic member}1 dependency: %2" - -- id: unexpected_provided_entity - msg: "unexpected provided entity: %0" - -- id: negative_expectation_violated - msg: "unexpected dependency exists: %0" - -- id: expectation_missing_opening_braces - msg: "expected {{ in expectation" - -- id: expectation_missing_closing_braces - msg: "didn't find '}}' to match '{{' in expectation" - -- id: module_incompatible_with_skip_function_bodies - msg: "module '%0' cannot be built with -experimental-skip-non-inlinable-function-bodies; this option has been automatically disabled" - -- id: warning_parallel_execution_not_supported - msg: "parallel execution not supported; falling back to serial execution" - -- id: error_unable_to_execute_command - msg: "unable to execute command: %0" - -- id: error_command_signalled_without_signal_number - msg: "%0 command failed due to signal (use -v to see invocation)" - -- id: error_command_signalled - msg: "%0 command failed due to signal %1 (use -v to see invocation)" - -- id: error_command_failed - msg: "%0 command failed with exit code %1 (use -v to see invocation)" - -- id: error_expected_one_frontend_job - msg: "unable to handle compilation, expected exactly one frontend job" - -- id: error_expected_frontend_command - msg: "expected a swift frontend command" - -- id: error_cannot_specify__o_for_multiple_outputs - msg: "cannot specify -o when generating multiple output files" - -- id: error_static_emit_executable_disallowed - msg: "-static may not be used with -emit-executable" - -- id: error_unable_to_load_output_file_map - msg: "unable to load output file map '%1': %0" - -- id: error_no_output_file_map_specified - msg: "no output file map specified" - -- id: error_unable_to_make_temporary_file - msg: "unable to make temporary file: %0" - -- id: error_no_input_files - msg: "no input files" - -- id: error_unexpected_input_file - msg: "unexpected input file: %0" - -- id: error_unknown_target - msg: "unknown target '%0'" - -- id: error_framework_bridging_header - msg: "using bridging headers with framework targets is unsupported" - -- id: error_bridging_header_module_interface - msg: "using bridging headers with module interfaces is unsupported" - -- id: error_i_mode - msg: "the flag '-i' is no longer required and has been removed; use '%0 input-filename'" - -- id: warning_unnecessary_repl_mode - msg: "unnecessary option '%0'; this is the default for '%1' with no input files" - -- id: error_unsupported_option - msg: "option '%0' is not supported by '%1'; did you mean to use '%2'?" - -- id: incremental_requires_output_file_map - msg: "ignoring -incremental (currently requires an output file map)" - -- id: incremental_requires_build_record_entry - msg: "ignoring -incremental; output file map has no master dependencies entry (\"%0\" under \"\")" - -- id: unable_to_open_incremental_comparison_log - msg: "unable to open incremental comparison log file '%0'" - -- id: error_os_minimum_deployment - msg: "Swift requires a minimum deployment target of %0" - -- id: error_sdk_too_old - msg: "Swift does not support the SDK '%0'" - -- id: error_ios_maximum_deployment_32 - msg: "iOS %0 does not support 32-bit programs" - -- id: error_unsupported_target_variant - msg: "unsupported '%select{-target|-target-variant}1' value '%0'; use 'ios-macabi' instead" - -- id: warn_arclite_not_found_when_link_objc_runtime - msg: "unable to find Objective-C runtime support library 'arclite'; pass '-no-link-objc-runtime' to silence this warning" - -- id: warn_cannot_stat_input - msg: "unable to determine when '%0' was last modified: %1" - -- id: warn_unable_to_load_dependencies - msg: "unable to load dependencies file \"%0\", disabling incremental mode" - -- id: error_input_changed_during_build - msg: "input file '%0' was modified during the build" - -- id: error_conflicting_options - msg: "conflicting options '%0' and '%1'" - -- id: error_option_not_supported - msg: "'%0' is not supported with '%1'" - -- id: error_requirement_not_met - msg: "'%0' requires '%1'" - -- id: warn_ignore_embed_bitcode - msg: "ignoring -embed-bitcode since no object file is being generated" - -- id: warn_ignore_embed_bitcode_marker - msg: "ignoring -embed-bitcode-marker since no object file is being generated" - -- id: verify_debug_info_requires_debug_option - msg: "ignoring '-verify-debug-info'; no debug info is being generated" - -- id: verify_incremental_dependencies_needs_incremental - msg: "'-verify-incremental-dependencies' requires '-incremental'" - -- id: error_profile_missing - msg: "no profdata file exists at '%0'" - -- id: warn_opt_remark_disabled - msg: "Emission of optimization records has been disabled, because it requires a single compiler invocation: consider enabling the -whole-module-optimization flag" - -- id: warn_ignoring_batch_mode - msg: "ignoring '-enable-batch-mode' because '%0' was also specified" - -- id: warn_ignoring_wmo - msg: "ignoring '-wmo' because '-dump-ast' was also specified" - -- id: warn_ignoring_source_range_dependencies - msg: "ignoring '-enable-source-range-dependencies' because '%0' was also specified" - -- id: warn_bad_swift_ranges_header - msg: "ignoring '-enable-source-range-dependencies' because of bad header in '%0'" - -- id: warn_bad_swift_ranges_format - msg: "ignoring '-enable-source-range-dependencies' because of bad format '%1' in '%0'" - -- id: warn_use_filelists_deprecated - msg: "the option '-driver-use-filelists' is deprecated; use '-driver-filelist-threshold=0' instead" - -- id: warn_unable_to_load_swift_ranges - msg: "unable to load swift ranges file \"%0\", %1" - -- id: warn_unable_to_load_compiled_swift - msg: "unable to load previously compiled swift file \"%0\", %1" - -- id: warn_unable_to_load_primary - msg: "unable to load primary swift file \"%0\", %1" - -- id: cannot_find_migration_script - msg: "missing migration script from path '%0'" - -- id: error_darwin_static_stdlib_not_supported - msg: "-static-stdlib is no longer supported on Apple platforms" - -- id: error_darwin_only_supports_libcxx - msg: "The only C++ standard library supported on Apple platforms is libc++" - -- id: warn_drv_darwin_sdk_invalid_settings - msg: "SDK settings were ignored because 'SDKSettings.json' could not be parsed" - -- id: invalid_name - msg: "'%0' is not a valid name" - -- id: invalid_location - msg: "given location is not valid" - -- id: arity_mismatch - msg: "the given new name '%0' does not match the arity of the old name '%1'" - -- id: name_not_functionlike - msg: "the 'call' name usage cannot be used with a non-function-like name '%0'" - -- id: unresolved_location - msg: "cannot resolve location as name" - -- id: location_module_mismatch - msg: "given location does not belong to module '%0'" - -- id: value_decl_no_loc - msg: "value decl '%0' has no declaration location" - -- id: value_decl_referenced_out_of_range - msg: "value decl '%0' is referenced out of range" - -- id: multi_entry_range - msg: "selected range has more than one entry point" - -- id: orphan_loop_keyword - msg: "selected range contains %0 but not its target loop" - -- id: invalid_default_location - msg: "given location is not on a default statement" - -- id: no_parent_switch - msg: "cannot find enclosing switch statement" - -- id: no_remaining_cases - msg: "no remaining cases to expand" - -- id: mismatched_rename - msg: "the name at the given location cannot be renamed to '%0'" - -- id: no_insert_position - msg: "cannot find inserting position" - -- id: generic_sig_change - msg: "%0 has generic signature change from %1 to %2" - -- id: raw_type_change - msg: "%0(%1) is now %2 representable" - -- id: removed_decl - msg: "%0 has been removed%select{| (deprecated)}1" - -- id: moved_decl - msg: "%0 has been moved to %1" - -- id: renamed_decl - msg: "%0 has been renamed to %1" - -- id: decl_type_change - msg: "%0 has %1 type change from %2 to %3" - -- id: decl_attr_change - msg: "%0 changes from %1 to %2" - -- id: decl_new_attr - msg: "%0 is now %1" - -- id: decl_reorder - msg: "%0 in a non-resilient type changes position from %1 to %2" - -- id: decl_added - msg: "%0 is added to a non-resilient type" - -- id: var_has_fixed_order_change - msg: "%0 is %select{now|no longer}1 a stored property" - -- id: func_has_fixed_order_change - msg: "%0 is %select{now|no longer}1 a non-final instance function" - -- id: default_arg_removed - msg: "%0 has removed default argument from %1" - -- id: conformance_removed - msg: "%0 has removed %select{conformance to|inherited protocol}2 %1" - -- id: conformance_added - msg: "%0 has added inherited protocol %1" - -- id: existing_conformance_added - msg: "%0 has added a conformance to an existing protocol %1" - -- id: default_associated_type_removed - msg: "%0 has removed default type %1" - -- id: protocol_req_added - msg: "%0 has been added as a protocol requirement" - -- id: super_class_removed - msg: "%0 has removed its super class %1" - -- id: super_class_changed - msg: "%0 has changed its super class from %1 to %2" - -- id: decl_kind_changed - msg: "%0 has been changed to a %1" - -- id: optional_req_changed - msg: "%0 is %select{now|no longer}1 an optional requirement" - -- id: no_longer_open - msg: "%0 is no longer open for subclassing" - -- id: func_type_escaping_changed - msg: "%0 has %select{removed|added}2 @escaping in %1" - -- id: func_self_access_change - msg: "%0 has self access kind changing from %1 to %2" - -- id: param_ownership_change - msg: "%0 has %1 changing from %2 to %3" - -- id: type_witness_change - msg: "%0 has type witness type for %1 changing from %2 to %3" - -- id: decl_new_witness_table_entry - msg: "%0 now requires %select{|no}1 new witness table entry" - -- id: new_decl_without_intro - msg: "%0 is a new API without @available attribute" - -- id: objc_name_change - msg: "%0 has ObjC name change from %1 to %2" - -- id: desig_init_added - msg: "%0 has been added as a designated initializer to an open class" - -- id: added_invisible_designated_init - msg: "%0 has new designated initializers that are not visible to clients" - -- id: not_inheriting_convenience_inits - msg: "%0 no longer inherits convenience inits from its superclass" - -- id: enum_case_added - msg: "%0 has been added as a new enum case" - diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 08a4083abdf15..b50cbc73b1f2b 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -22,6 +22,7 @@ add_swift_tool_subdirectory(swift-ide-test) add_swift_tool_subdirectory(swift-remoteast-test) add_swift_tool_subdirectory(swift-demangle) add_swift_tool_subdirectory(swift-demangle-yamldump) +add_swift_tool_subdirectory(swift-def-to-yaml-converter) add_swift_tool_subdirectory(swift-serialize-diagnostics) add_swift_tool_subdirectory(lldb-moduleimport-test) add_swift_tool_subdirectory(sil-func-extractor) diff --git a/tools/swift-def-to-yaml-converter/CMakeLists.txt b/tools/swift-def-to-yaml-converter/CMakeLists.txt new file mode 100644 index 0000000000000..29339d2d7440e --- /dev/null +++ b/tools/swift-def-to-yaml-converter/CMakeLists.txt @@ -0,0 +1,8 @@ +add_swift_host_tool(swift-def-to-yaml-converter + swift-def-to-yaml-converter.cpp + SWIFT_COMPONENT tools +) + +target_link_libraries(swift-def-to-yaml-converter PRIVATE + swiftLocalization + swiftAST) diff --git a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp new file mode 100644 index 0000000000000..64a3ebf0935b5 --- /dev/null +++ b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp @@ -0,0 +1,94 @@ +//===--- swift-def-to-yaml-converter.cpp ----------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Create a YAML file from the diagnostic messages text in `.def` files. +// +//===----------------------------------------------------------------------===// + +#include "swift/Basic/LLVMInitialize.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include + +static constexpr const char *const diagnosticID[] = { +#define DIAG(KIND, ID, Options, Text, Signature) #ID, +#include "swift/AST/DiagnosticsAll.def" +}; + +static constexpr const char *const diagnosticMessages[] = { +#define DIAG(KIND, ID, Options, Text, Signature) Text, +#include "swift/AST/DiagnosticsAll.def" +}; + +enum LocalDiagID : uint32_t { +#define DIAG(KIND, ID, Options, Text, Signature) ID, +#include "swift/AST/DiagnosticsAll.def" + NumDiags +}; + +namespace options { + +static llvm::cl::OptionCategory Category("swift-def-to-yaml-converter Options"); + +static llvm::cl::opt + OutputDirectory("output-directory", + llvm::cl::desc("Directory for the output file"), + llvm::cl::cat(Category)); + +} // namespace options + +int main(int argc, char *argv[]) { + PROGRAM_START(argc, argv); + + llvm::cl::HideUnrelatedOptions(options::Category); + llvm::cl::ParseCommandLineOptions(argc, argv, + "Swift `.def` to YAML Converter\n"); + + // The default language for localization is English + std::string defaultLocaleCode = "en"; + llvm::SmallString<128> LocalizedFilePath(options::OutputDirectory); + llvm::sys::path::append(LocalizedFilePath, defaultLocaleCode); + llvm::sys::path::replace_extension(LocalizedFilePath, ".yaml"); + + std::error_code error; + llvm::raw_fd_ostream OS(LocalizedFilePath.str(), error, + llvm::sys::fs::F_None); + + for (unsigned i = 0; i < LocalDiagID::NumDiags; ++i) { + OS << "- id: " << diagnosticID[i] << "\n"; + std::string msg = diagnosticMessages[i]; + std::string finalMsg = ""; + + // Add an escape character before a double quote `"` or a backslash `\`. + for (unsigned j = 0; j < msg.length(); ++j) { + if (msg[j] == '"') { + finalMsg += '\\'; + finalMsg += '"'; + } else if (msg[j] == '\\') { + finalMsg += '\\'; + finalMsg += '\\'; + } else { + finalMsg += msg[j]; + } + } + OS << " msg: \"" << finalMsg << "\"\r\n"; + } + + return EXIT_SUCCESS; +} diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 0aa744d919f6c..17d2439dff45f 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -9,6 +9,7 @@ if(SWIFT_INCLUDE_TOOLS) add_subdirectory(ClangImporter) add_subdirectory(Driver) add_subdirectory(FrontendTool) + add_subdirectory(DefToYAMLConverter) add_subdirectory(IDE) add_subdirectory(Parse) add_subdirectory(SwiftDemangle) diff --git a/unittests/DefToYAMLConverter/CMakeLists.txt b/unittests/DefToYAMLConverter/CMakeLists.txt new file mode 100644 index 0000000000000..b16f129128d5c --- /dev/null +++ b/unittests/DefToYAMLConverter/CMakeLists.txt @@ -0,0 +1,9 @@ +add_swift_unittest(DefToYAMLConverterTest + DefToYAMLConverterTest.cpp) + +target_link_libraries(DefToYAMLConverterTest + PRIVATE + swiftLocalization) + +target_compile_definitions(DefToYAMLConverterTest PRIVATE + SWIFTLIB_DIR=\"${SWIFTLIB_DIR}\") diff --git a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp new file mode 100644 index 0000000000000..0daa52b0b2035 --- /dev/null +++ b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp @@ -0,0 +1,60 @@ +//===--- DefToYAMLConverterTest.cpp --------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +using namespace swift; +using namespace swift::diag; + +static constexpr const char *const diagnosticMessages[] = { +#define DIAG(KIND, ID, Options, Text, Signature) Text, +#include "swift/AST/DiagnosticsAll.def" +}; + +static std::string getDefaultLocalizationPath() { + std::string libPath = llvm::sys::path::parent_path(SWIFTLIB_DIR); + llvm::SmallString<128> DefaultDiagnosticMessagesDir(libPath); + llvm::sys::path::remove_filename(DefaultDiagnosticMessagesDir); // Remove /lib + llvm::sys::path::remove_filename(DefaultDiagnosticMessagesDir); // Remove /. + llvm::sys::path::append(DefaultDiagnosticMessagesDir, "share", "swift", + "diagnostics"); + return std::string(DefaultDiagnosticMessagesDir.str()); +} + +TEST(DefToYAMLConverterTest, missingLocalizationFiles) { + ASSERT_TRUE(llvm::sys::fs::exists(getDefaultLocalizationPath())); + llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); + llvm::sys::path::append(EnglishLocalization, "en"); + llvm::sys::path::replace_extension(EnglishLocalization, ".yaml"); + ASSERT_TRUE(llvm::sys::fs::exists(EnglishLocalization)); + llvm::sys::path::replace_extension(EnglishLocalization, ".db"); + ASSERT_TRUE(llvm::sys::fs::exists(EnglishLocalization)); +} + +TEST(DefToYAMLConverterTest, matchDiagnosticMessages) { + llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); + llvm::sys::path::append(EnglishLocalization, "en"); + llvm::sys::path::replace_extension(EnglishLocalization, ".yaml"); + YAMLLocalizationProducer yaml(EnglishLocalization.str()); + + yaml.forEachAvailable([](swift::DiagID id, llvm::StringRef translation) { + ASSERT_TRUE(diagnosticMessages[static_cast(id)] == translation); + }); +} From 4a84c0a6065029eb3cbaeb5ae4fb475848e2803f Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Fri, 28 Aug 2020 03:07:46 +0200 Subject: [PATCH 554/663] [unittests] Add `matchDiagnosticMessagesRandomly` --- .../DefToYAMLConverterTest.cpp | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp index 0daa52b0b2035..de3dd30da6e82 100644 --- a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp +++ b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp @@ -19,10 +19,17 @@ #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" +#include using namespace swift; using namespace swift::diag; +enum LocalDiagID : uint32_t { +#define DIAG(KIND, ID, Options, Text, Signature) ID, +#include "swift/AST/DiagnosticsAll.def" + NumDiags +}; + static constexpr const char *const diagnosticMessages[] = { #define DIAG(KIND, ID, Options, Text, Signature) Text, #include "swift/AST/DiagnosticsAll.def" @@ -38,6 +45,9 @@ static std::string getDefaultLocalizationPath() { return std::string(DefaultDiagnosticMessagesDir.str()); } +/// Random number in [0,n) +unsigned randNum(unsigned n) { return unsigned(rand()) % n; } + TEST(DefToYAMLConverterTest, missingLocalizationFiles) { ASSERT_TRUE(llvm::sys::fs::exists(getDefaultLocalizationPath())); llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); @@ -48,7 +58,7 @@ TEST(DefToYAMLConverterTest, missingLocalizationFiles) { ASSERT_TRUE(llvm::sys::fs::exists(EnglishLocalization)); } -TEST(DefToYAMLConverterTest, matchDiagnosticMessages) { +TEST(DefToYAMLConverterTest, matchDiagnosticMessagesSequentially) { llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); llvm::sys::path::append(EnglishLocalization, "en"); llvm::sys::path::replace_extension(EnglishLocalization, ".yaml"); @@ -58,3 +68,21 @@ TEST(DefToYAMLConverterTest, matchDiagnosticMessages) { ASSERT_TRUE(diagnosticMessages[static_cast(id)] == translation); }); } + +TEST(DefToYAMLConverterTest, matchDiagnosticMessagesRandomly) { + llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); + llvm::sys::path::append(EnglishLocalization, "en"); + llvm::sys::path::replace_extension(EnglishLocalization, ".yaml"); + YAMLLocalizationProducer yaml(EnglishLocalization.str()); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> distr(50, LocalDiagID::NumDiags); + unsigned numberOfQueries = distr(gen); + while (numberOfQueries--) { + unsigned randomNum = randNum(LocalDiagID::NumDiags); + DiagID randomId = static_cast(randomNum); + ASSERT_TRUE(yaml.getMessageOr(randomId, "") == + diagnosticMessages[randomNum]); + } +} From a0dc80e09608a88acf588b4e2070b6f4f3efddb8 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Fri, 28 Aug 2020 05:56:21 +0200 Subject: [PATCH 555/663] [unittests] Use ASSERT_EQ --- unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp index de3dd30da6e82..de2f14034cfc1 100644 --- a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp +++ b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp @@ -65,7 +65,8 @@ TEST(DefToYAMLConverterTest, matchDiagnosticMessagesSequentially) { YAMLLocalizationProducer yaml(EnglishLocalization.str()); yaml.forEachAvailable([](swift::DiagID id, llvm::StringRef translation) { - ASSERT_TRUE(diagnosticMessages[static_cast(id)] == translation); + llvm::StringRef msg = diagnosticMessages[static_cast(id)]; + ASSERT_EQ(msg, translation); }); } @@ -82,7 +83,8 @@ TEST(DefToYAMLConverterTest, matchDiagnosticMessagesRandomly) { while (numberOfQueries--) { unsigned randomNum = randNum(LocalDiagID::NumDiags); DiagID randomId = static_cast(randomNum); - ASSERT_TRUE(yaml.getMessageOr(randomId, "") == - diagnosticMessages[randomNum]); + llvm::StringRef msg = diagnosticMessages[randomNum]; + llvm::StringRef translation = yaml.getMessageOr(randomId, ""); + ASSERT_EQ(msg, translation); } } From b17dd271abbc1359c157f80815954277d646a525 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Fri, 28 Aug 2020 06:22:46 +0200 Subject: [PATCH 556/663] [tools] Remove swiftAST dependency --- tools/swift-def-to-yaml-converter/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/swift-def-to-yaml-converter/CMakeLists.txt b/tools/swift-def-to-yaml-converter/CMakeLists.txt index 29339d2d7440e..558a737c8257e 100644 --- a/tools/swift-def-to-yaml-converter/CMakeLists.txt +++ b/tools/swift-def-to-yaml-converter/CMakeLists.txt @@ -4,5 +4,4 @@ add_swift_host_tool(swift-def-to-yaml-converter ) target_link_libraries(swift-def-to-yaml-converter PRIVATE - swiftLocalization - swiftAST) + swiftLocalization) From 3f4081233c570d880271b9888cfd3b8647d5e9e7 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Sat, 29 Aug 2020 07:22:04 +0200 Subject: [PATCH 557/663] [tools] [unittests] Add missing include headers --- .../swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp | 2 ++ unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp index 64a3ebf0935b5..cfd4fca591320 100644 --- a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp +++ b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp @@ -25,6 +25,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include +#include +#include static constexpr const char *const diagnosticID[] = { #define DIAG(KIND, ID, Options, Text, Signature) #ID, diff --git a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp index de2f14034cfc1..fae3f5b7ced3f 100644 --- a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp +++ b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" #include +#include using namespace swift; using namespace swift::diag; From 8e860e4701a0e7d74d41965fc20170e747f66dc8 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Sat, 29 Aug 2020 07:31:49 +0200 Subject: [PATCH 558/663] [tools] Handle errors when opening the YAML file --- .../swift-def-to-yaml-converter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp index cfd4fca591320..aa58cb97215cb 100644 --- a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp +++ b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp @@ -72,6 +72,11 @@ int main(int argc, char *argv[]) { llvm::raw_fd_ostream OS(LocalizedFilePath.str(), error, llvm::sys::fs::F_None); + if (OS.has_error() || error) { + llvm::errs() << LocalizedFilePath.str() << " does not exist\n"; + return EXIT_FAILURE; + } + for (unsigned i = 0; i < LocalDiagID::NumDiags; ++i) { OS << "- id: " << diagnosticID[i] << "\n"; std::string msg = diagnosticMessages[i]; From e5c42e4191c65c6788a30335c59df576d26da2d0 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Sat, 29 Aug 2020 08:55:22 +0200 Subject: [PATCH 559/663] [Localization] Add .gitkeep in diagnostics folder --- localization/diagnostics/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 localization/diagnostics/.gitkeep diff --git a/localization/diagnostics/.gitkeep b/localization/diagnostics/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d From d8a16d1d4492c2f304803960a3bd076a132aa81e Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Mon, 31 Aug 2020 15:24:14 +0200 Subject: [PATCH 560/663] [tools] Improve error message and add `output-filename` as an option --- .../swift-def-to-yaml-converter.cpp | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp index aa58cb97215cb..2087943e7d7ce 100644 --- a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp +++ b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp @@ -53,6 +53,11 @@ static llvm::cl::opt llvm::cl::desc("Directory for the output file"), llvm::cl::cat(Category)); +static llvm::cl::opt + OutputFilename("output-filename", + llvm::cl::desc("Filename for the output file"), + llvm::cl::cat(Category)); + } // namespace options int main(int argc, char *argv[]) { @@ -62,18 +67,25 @@ int main(int argc, char *argv[]) { llvm::cl::ParseCommandLineOptions(argc, argv, "Swift `.def` to YAML Converter\n"); - // The default language for localization is English - std::string defaultLocaleCode = "en"; - llvm::SmallString<128> LocalizedFilePath(options::OutputDirectory); - llvm::sys::path::append(LocalizedFilePath, defaultLocaleCode); - llvm::sys::path::replace_extension(LocalizedFilePath, ".yaml"); + llvm::SmallString<128> LocalizedFilePath; + if (options::OutputFilename.empty()) { + // The default language for localization is English + std::string defaultLocaleCode = "en"; + LocalizedFilePath = options::OutputDirectory; + llvm::sys::path::append(LocalizedFilePath, defaultLocaleCode); + llvm::sys::path::replace_extension(LocalizedFilePath, ".yaml"); + } else { + LocalizedFilePath = options::OutputFilename; + } std::error_code error; llvm::raw_fd_ostream OS(LocalizedFilePath.str(), error, llvm::sys::fs::F_None); if (OS.has_error() || error) { - llvm::errs() << LocalizedFilePath.str() << " does not exist\n"; + llvm::errs() << "Error has occurred while trying to write to " + << LocalizedFilePath.str() + << " with error code: " << error.message() << "\n"; return EXIT_FAILURE; } From 7124d4aacb66e4c6c95388a2a64e563c9dfe8f66 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Mon, 31 Aug 2020 20:07:02 +0200 Subject: [PATCH 561/663] [unittests] Make tests call the converter on temp files --- .../DefToYAMLConverterTest.cpp | 55 +++++++++++++++---- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp index fae3f5b7ced3f..a9aaf32304a6a 100644 --- a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp +++ b/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp @@ -15,12 +15,16 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" +#include #include #include +#include using namespace swift; using namespace swift::diag; @@ -36,16 +40,28 @@ static constexpr const char *const diagnosticMessages[] = { #include "swift/AST/DiagnosticsAll.def" }; -static std::string getDefaultLocalizationPath() { +static std::string getMainExecutablePath() { std::string libPath = llvm::sys::path::parent_path(SWIFTLIB_DIR); - llvm::SmallString<128> DefaultDiagnosticMessagesDir(libPath); - llvm::sys::path::remove_filename(DefaultDiagnosticMessagesDir); // Remove /lib - llvm::sys::path::remove_filename(DefaultDiagnosticMessagesDir); // Remove /. + llvm::SmallString<128> MainExecutablePath(libPath); + llvm::sys::path::remove_filename(MainExecutablePath); // Remove /lib + llvm::sys::path::remove_filename(MainExecutablePath); // Remove /. + return std::string(MainExecutablePath.str()); +} + +static std::string getDefaultLocalizationPath() { + llvm::SmallString<128> DefaultDiagnosticMessagesDir(getMainExecutablePath()); llvm::sys::path::append(DefaultDiagnosticMessagesDir, "share", "swift", "diagnostics"); return std::string(DefaultDiagnosticMessagesDir.str()); } +static std::string getDefToYAMLConverterPath() { + llvm::SmallString<128> defYAMLConverter(getMainExecutablePath()); + llvm::sys::path::append(defYAMLConverter, "bin", + "swift-def-to-yaml-converter"); + return std::string(defYAMLConverter.str()); +} + /// Random number in [0,n) unsigned randNum(unsigned n) { return unsigned(rand()) % n; } @@ -60,11 +76,18 @@ TEST(DefToYAMLConverterTest, missingLocalizationFiles) { } TEST(DefToYAMLConverterTest, matchDiagnosticMessagesSequentially) { - llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); - llvm::sys::path::append(EnglishLocalization, "en"); - llvm::sys::path::replace_extension(EnglishLocalization, ".yaml"); - YAMLLocalizationProducer yaml(EnglishLocalization.str()); + llvm::SmallString<128> defYAMLConverter(getDefToYAMLConverterPath()); + defYAMLConverter.append(" --output-filename="); + + llvm::SmallString<128> tempFilename; + std::error_code EC = + llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); + ASSERT_FALSE(EC); + llvm::sys::RemoveFileOnSignal(tempFilename); + defYAMLConverter.append(tempFilename); + std::system(defYAMLConverter.c_str()); + YAMLLocalizationProducer yaml(tempFilename.str()); yaml.forEachAvailable([](swift::DiagID id, llvm::StringRef translation) { llvm::StringRef msg = diagnosticMessages[static_cast(id)]; ASSERT_EQ(msg, translation); @@ -72,10 +95,18 @@ TEST(DefToYAMLConverterTest, matchDiagnosticMessagesSequentially) { } TEST(DefToYAMLConverterTest, matchDiagnosticMessagesRandomly) { - llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); - llvm::sys::path::append(EnglishLocalization, "en"); - llvm::sys::path::replace_extension(EnglishLocalization, ".yaml"); - YAMLLocalizationProducer yaml(EnglishLocalization.str()); + llvm::SmallString<128> defYAMLConverter(getDefToYAMLConverterPath()); + defYAMLConverter.append(" --output-filename="); + + llvm::SmallString<128> tempFilename; + std::error_code EC = + llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); + ASSERT_FALSE(EC); + llvm::sys::RemoveFileOnSignal(tempFilename); + defYAMLConverter.append(tempFilename); + std::system(defYAMLConverter.c_str()); + + YAMLLocalizationProducer yaml(tempFilename.str()); std::random_device rd; std::mt19937 gen(rd()); From b51b1f121e48e2f4b0c7cfdd54c31d4367d06d77 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 2 Sep 2020 12:10:21 -0700 Subject: [PATCH 562/663] [Localization] Establish dependency between def-to-yaml converter and diagnostic-database --- localization/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index b880dd9460f89..53c7e05e2a757 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -14,6 +14,7 @@ add_custom_command(TARGET diagnostic-database add_dependencies(swift-frontend diagnostic-database) add_dependencies(diagnostic-database swift-serialize-diagnostics) +add_dependencies(diagnostic-database swift-def-to-yaml-converter) swift_install_in_component( DIRECTORY ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ From 5d11fe6b62df42088baf18f713dfac5a0813edd4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 2 Sep 2020 15:48:06 -0700 Subject: [PATCH 563/663] [Localization] Extract def-to-yaml conversion logic into `DefToYAMLConverter` to ease testing --- .../swift/Localization/LocalizationFormat.h | 15 +++++++++++ lib/Localization/LocalizationFormat.cpp | 24 +++++++++++++++++ .../swift-def-to-yaml-converter.cpp | 27 ++++++------------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/include/swift/Localization/LocalizationFormat.h b/include/swift/Localization/LocalizationFormat.h index efd3d5345467f..ccea86711d6c3 100644 --- a/include/swift/Localization/LocalizationFormat.h +++ b/include/swift/Localization/LocalizationFormat.h @@ -17,6 +17,7 @@ #ifndef SWIFT_LOCALIZATIONFORMAT_H #define SWIFT_LOCALIZATIONFORMAT_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" @@ -42,6 +43,20 @@ namespace diag { using namespace llvm::support; +class DefToYAMLConverter { + llvm::ArrayRef IDs; + llvm::ArrayRef Messages; + +public: + DefToYAMLConverter(llvm::ArrayRef ids, + llvm::ArrayRef messages) + : IDs(ids), Messages(messages) { + assert(IDs.size() == Messages.size()); + } + + void convert(llvm::raw_ostream &out); +}; + class LocalizationWriterInfo { public: using key_type = uint32_t; diff --git a/lib/Localization/LocalizationFormat.cpp b/lib/Localization/LocalizationFormat.cpp index 750a43651301a..94f73b159acaa 100644 --- a/lib/Localization/LocalizationFormat.cpp +++ b/lib/Localization/LocalizationFormat.cpp @@ -14,6 +14,7 @@ // //===----------------------------------------------------------------------===// +#include "swift/Basic/Range.h" #include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" @@ -190,5 +191,28 @@ operator>>(LocalizationInput &yin, T &diagnostics) { return yin; } +void DefToYAMLConverter::convert(llvm::raw_ostream &out) { + for (auto i : swift::indices(IDs)) { + out << "- id: " << IDs[i] << "\n"; + + const std::string &msg = Messages[i]; + + out << " msg: \""; + // Add an escape character before a double quote `"` or a backslash `\`. + for (unsigned j = 0; j < msg.length(); ++j) { + if (msg[j] == '"') { + out << '\\'; + out << '"'; + } else if (msg[j] == '\\') { + out << '\\'; + out << '\\'; + } else { + out << msg[j]; + } + } + out << "\"\r\n"; + } +} + } // namespace diag } // namespace swift diff --git a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp index 2087943e7d7ce..0d49088111374 100644 --- a/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp +++ b/tools/swift-def-to-yaml-converter/swift-def-to-yaml-converter.cpp @@ -15,6 +15,8 @@ //===----------------------------------------------------------------------===// #include "swift/Basic/LLVMInitialize.h" +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" @@ -89,25 +91,12 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - for (unsigned i = 0; i < LocalDiagID::NumDiags; ++i) { - OS << "- id: " << diagnosticID[i] << "\n"; - std::string msg = diagnosticMessages[i]; - std::string finalMsg = ""; - - // Add an escape character before a double quote `"` or a backslash `\`. - for (unsigned j = 0; j < msg.length(); ++j) { - if (msg[j] == '"') { - finalMsg += '\\'; - finalMsg += '"'; - } else if (msg[j] == '\\') { - finalMsg += '\\'; - finalMsg += '\\'; - } else { - finalMsg += msg[j]; - } - } - OS << " msg: \"" << finalMsg << "\"\r\n"; - } + llvm::ArrayRef ids(diagnosticID, LocalDiagID::NumDiags); + llvm::ArrayRef messages(diagnosticMessages, + LocalDiagID::NumDiags); + + swift::diag::DefToYAMLConverter converter(ids, messages); + converter.convert(OS); return EXIT_SUCCESS; } From dbae8342e8e596553ac7b62ec19afc9ff545ea4f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 3 Sep 2020 12:06:43 -0700 Subject: [PATCH 564/663] [Localization] Establish a dedicated directory for localization tests --- unittests/CMakeLists.txt | 2 +- unittests/DefToYAMLConverter/CMakeLists.txt | 9 --------- unittests/Localization/CMakeLists.txt | 9 +++++++++ .../DefToYAMLConverterTests.cpp} | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 unittests/DefToYAMLConverter/CMakeLists.txt create mode 100644 unittests/Localization/CMakeLists.txt rename unittests/{DefToYAMLConverter/DefToYAMLConverterTest.cpp => Localization/DefToYAMLConverterTests.cpp} (98%) diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 17d2439dff45f..5c6daa804cff8 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -9,7 +9,7 @@ if(SWIFT_INCLUDE_TOOLS) add_subdirectory(ClangImporter) add_subdirectory(Driver) add_subdirectory(FrontendTool) - add_subdirectory(DefToYAMLConverter) + add_subdirectory(Localization) add_subdirectory(IDE) add_subdirectory(Parse) add_subdirectory(SwiftDemangle) diff --git a/unittests/DefToYAMLConverter/CMakeLists.txt b/unittests/DefToYAMLConverter/CMakeLists.txt deleted file mode 100644 index b16f129128d5c..0000000000000 --- a/unittests/DefToYAMLConverter/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_swift_unittest(DefToYAMLConverterTest - DefToYAMLConverterTest.cpp) - -target_link_libraries(DefToYAMLConverterTest - PRIVATE - swiftLocalization) - -target_compile_definitions(DefToYAMLConverterTest PRIVATE - SWIFTLIB_DIR=\"${SWIFTLIB_DIR}\") diff --git a/unittests/Localization/CMakeLists.txt b/unittests/Localization/CMakeLists.txt new file mode 100644 index 0000000000000..e43fe72f0d451 --- /dev/null +++ b/unittests/Localization/CMakeLists.txt @@ -0,0 +1,9 @@ +add_swift_unittest(swiftLocalizationTests + DefToYAMLConverterTests.cpp) + +target_link_libraries(swiftLocalizationTests + PRIVATE + swiftLocalization) + +target_compile_definitions(swiftLocalizationTests PRIVATE + SWIFTLIB_DIR=\"${SWIFTLIB_DIR}\") diff --git a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp b/unittests/Localization/DefToYAMLConverterTests.cpp similarity index 98% rename from unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp rename to unittests/Localization/DefToYAMLConverterTests.cpp index a9aaf32304a6a..c7d5f47bfd6af 100644 --- a/unittests/DefToYAMLConverter/DefToYAMLConverterTest.cpp +++ b/unittests/Localization/DefToYAMLConverterTests.cpp @@ -1,4 +1,4 @@ -//===--- DefToYAMLConverterTest.cpp --------------------------------------===// +//===--- DefToYAMLConverterTests.cpp -------------------------------------===// // // This source file is part of the Swift.org open source project // From 73a5279a0b2a8bb3b3a7c72efbd9cbb13282be6f Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 3 Sep 2020 17:20:43 -0700 Subject: [PATCH 565/663] [docs] Add 'critical edge' definition to Lexicon. (#33765) --- docs/Lexicon.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/Lexicon.md b/docs/Lexicon.md index 32e2d4acd8dfa..bc8ed1e9465d8 100644 --- a/docs/Lexicon.md +++ b/docs/Lexicon.md @@ -111,6 +111,11 @@ the AST level. See also [witness table](#witness-table). context. This type may contain [archetypes](#archetype) and cannot be used directly from outside the context. Compare with [interface type](#interface-type). +## critical edge + +An edge in a control flow graph where the destination has multiple predecessors +and the source has multiple successors. + ## customization point Informal term for a protocol requirement that has a default implementation, From e97a6ffb0159f62ba42948a0b44aee03e4a202f3 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 3 Sep 2020 15:30:54 -0700 Subject: [PATCH 566/663] swift_build_sdk_interfaces.py: copy SDK build version file into prebuilt module cache directory This could help us track which version of SDK the module cache were built from. --- utils/swift_build_sdk_interfaces.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/utils/swift_build_sdk_interfaces.py b/utils/swift_build_sdk_interfaces.py index c8381193a9bd4..140afabdb9d3d 100755 --- a/utils/swift_build_sdk_interfaces.py +++ b/utils/swift_build_sdk_interfaces.py @@ -12,6 +12,7 @@ import subprocess import sys import traceback +from shutil import copyfile BARE_INTERFACE_SEARCH_PATHS = [ "usr/lib/swift", @@ -362,6 +363,16 @@ def getSDKVersion(sdkroot): fatal("Failed to get SDK version from: " + settingPath) +def copySystemVersionFile(sdkroot, output): + sysInfoPath = os.path.join(sdkroot, + 'System/Library/CoreServices/SystemVersion.plist') + destInfoPath = os.path.join(output, 'SystemVersion.plist') + try: + copyfile(sysInfoPath, destInfoPath) + except BaseException as e: + print("cannot copy from " + sysInfoPath + " to " + destInfoPath + ": " + str(e)) + + def main(): global args, shared_output_lock parser = create_parser() @@ -398,6 +409,10 @@ def main(): xfails = json.load(xfails_file) make_dirs_if_needed(args.output_dir, args.dry_run) + + # Copy a file containing SDK build version into the prebuilt module dir, + # so we can keep track of the SDK version we built from. + copySystemVersionFile(args.sdk, args.output_dir) if 'ANDROID_DATA' not in os.environ: shared_output_lock = multiprocessing.Lock() pool = multiprocessing.Pool(args.jobs, set_up_child, From 41f1285b993fc2707248b14cbb309bd8f7f00e9a Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Thu, 3 Sep 2020 18:43:52 -0700 Subject: [PATCH 567/663] Don't use lookupSymbol when SWIFT_RUNTIME_MACHO_NO_DYLD (#33792) --- stdlib/public/runtime/MetadataLookup.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index c0c2f7c0c4c9d..fef3ff3f82e76 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -975,11 +975,13 @@ _gatherGenericParameters(const ContextDescriptor *context, str += "_gatherGenericParameters: context: "; +#if !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) SymbolInfo contextInfo; if (lookupSymbol(context, &contextInfo)) { str += contextInfo.symbolName.get(); str += " "; } +#endif char *contextStr; swift_asprintf(&contextStr, "%p", context); From ea6cae658ed08ff843ee02c0cd89d17988ba891c Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Thu, 3 Sep 2020 18:44:47 -0700 Subject: [PATCH 568/663] Make waiting on condition variables error out on SWIFT_STDLIB_SINGLE_THREADED_RUNTIME (#33788) --- include/swift/Runtime/MutexSingleThreaded.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/swift/Runtime/MutexSingleThreaded.h b/include/swift/Runtime/MutexSingleThreaded.h index 4a25e9091b3d5..b7323c4b67389 100644 --- a/include/swift/Runtime/MutexSingleThreaded.h +++ b/include/swift/Runtime/MutexSingleThreaded.h @@ -17,6 +17,8 @@ #ifndef SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H #define SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H +#include "swift/Runtime/Debug.h" + namespace swift { typedef void* ConditionHandle; @@ -35,7 +37,9 @@ struct ConditionPlatformHelper { static void destroy(ConditionHandle &condition) {} static void notifyOne(ConditionHandle &condition) {} static void notifyAll(ConditionHandle &condition) {} - static void wait(ConditionHandle &condition, MutexHandle &mutex); + static void wait(ConditionHandle &condition, MutexHandle &mutex) { + fatalError(0, "single-threaded runtime cannot wait for condition"); + } }; struct MutexPlatformHelper { From 77b4f756088ac751ec33e099ab71c4c446b08171 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 3 Sep 2020 09:21:11 -0700 Subject: [PATCH 569/663] [SourceKit] Reorgantize code completion options * Abolish 'reuseastcontext' per-request option * Add 'MaxASTContextReuseCount' global configuration --- include/swift/IDE/CompletionInstance.h | 14 ++++-- lib/IDE/CompletionInstance.cpp | 49 +++++++++---------- .../complete_checkdeps_avoid_check.swift | 2 +- .../complete_checkdeps_bridged.swift | 2 +- .../complete_checkdeps_clangmodule.swift | 2 +- .../complete_checkdeps_otherfile.swift | 2 +- .../complete_checkdeps_ownfile.swift | 2 +- .../complete_checkdeps_swiftmodule.swift | 2 +- .../CodeComplete/complete_checkdeps_vfs.swift | 2 +- .../complete_checkdeps_vfs_open.swift | 2 +- .../CodeComplete/complete_sequence.swift | 5 +- .../CodeComplete/complete_sequence_race.swift | 26 +++++----- .../complete_without_stdlib.swift | 5 +- test/SourceKit/ConformingMethods/basic.swift | 7 ++- .../CursorInfo/use-swift-source-info.swift | 4 +- .../TypeContextInfo/typecontext_basic.swift | 7 ++- .../include/SourceKit/Core/Context.h | 17 +++++-- tools/SourceKit/lib/Core/Context.cpp | 12 +++-- .../lib/SwiftLang/CodeCompletionOrganizer.h | 1 - .../lib/SwiftLang/SwiftCompletion.cpp | 9 +--- .../SwiftLang/SwiftConformingMethodList.cpp | 15 +++--- .../lib/SwiftLang/SwiftLangSupport.cpp | 12 +++-- .../lib/SwiftLang/SwiftLangSupport.h | 6 +-- .../lib/SwiftLang/SwiftTypeContextInfo.cpp | 11 ++--- .../tools/sourcekitd-test/Options.td | 8 --- .../tools/sourcekitd-test/TestOptions.cpp | 23 --------- .../tools/sourcekitd-test/sourcekitd-test.cpp | 20 ++++---- .../tools/sourcekitd/lib/API/Requests.cpp | 24 +++++---- tools/swift-ide-test/swift-ide-test.cpp | 5 +- utils/gyb_sourcekit_support/UIDs.py | 2 + 30 files changed, 144 insertions(+), 154 deletions(-) diff --git a/include/swift/IDE/CompletionInstance.h b/include/swift/IDE/CompletionInstance.h index 51687b974b9c0..2c114ee194e4c 100644 --- a/include/swift/IDE/CompletionInstance.h +++ b/include/swift/IDE/CompletionInstance.h @@ -37,8 +37,10 @@ makeCodeCompletionMemoryBuffer(const llvm::MemoryBuffer *origBuf, /// Manages \c CompilerInstance for completion like operations. class CompletionInstance { - unsigned MaxASTReuseCount = 100; - unsigned DependencyCheckIntervalSecond = 5; + struct Options { + unsigned MaxASTReuseCount = 100; + unsigned DependencyCheckIntervalSecond = 5; + } Opts; std::mutex mtx; @@ -59,7 +61,7 @@ class CompletionInstance { /// argument has changed, primary file is not the same, the \c Offset is not /// in function bodies, or the interface hash of the file has changed. bool performCachedOperationIfPossible( - const swift::CompilerInvocation &Invocation, llvm::hash_code ArgsHash, + llvm::hash_code ArgsHash, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, DiagnosticConsumer *DiagC, @@ -78,7 +80,9 @@ class CompletionInstance { llvm::function_ref Callback); public: - void setDependencyCheckIntervalSecond(unsigned Value); + CompletionInstance() {} + + void setOptions(Options NewOpts); /// Calls \p Callback with a \c CompilerInstance which is prepared for the /// second pass. \p Callback is resposible to perform the second pass on it. @@ -94,7 +98,7 @@ class CompletionInstance { swift::CompilerInvocation &Invocation, llvm::ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, - bool EnableASTCaching, std::string &Error, DiagnosticConsumer *DiagC, + std::string &Error, DiagnosticConsumer *DiagC, llvm::function_ref Callback); }; diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 5b3c891bfacae..2c2babd019b7c 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -275,7 +275,7 @@ static bool areAnyDependentFilesInvalidated( } // namespace bool CompletionInstance::performCachedOperationIfPossible( - const swift::CompilerInvocation &Invocation, llvm::hash_code ArgsHash, + llvm::hash_code ArgsHash, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, DiagnosticConsumer *DiagC, @@ -285,7 +285,7 @@ bool CompletionInstance::performCachedOperationIfPossible( if (!CachedCI) return false; - if (CachedReuseCount >= MaxASTReuseCount) + if (CachedReuseCount >= Opts.MaxASTReuseCount) return false; if (CachedArgHash != ArgsHash) return false; @@ -570,20 +570,21 @@ bool CompletionInstance::shouldCheckDependencies() const { assert(CachedCI); using namespace std::chrono; auto now = system_clock::now(); - return DependencyCheckedTimestamp + seconds(DependencyCheckIntervalSecond) < - now; + auto threshold = DependencyCheckedTimestamp + + seconds(Opts.DependencyCheckIntervalSecond); + return threshold < now; } -void CompletionInstance::setDependencyCheckIntervalSecond(unsigned Value) { +void CompletionInstance::setOptions(CompletionInstance::Options NewOpts) { std::lock_guard lock(mtx); - DependencyCheckIntervalSecond = Value; + Opts = NewOpts; } bool swift::ide::CompletionInstance::performOperation( swift::CompilerInvocation &Invocation, llvm::ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, llvm::MemoryBuffer *completionBuffer, unsigned int Offset, - bool EnableASTCaching, std::string &Error, DiagnosticConsumer *DiagC, + std::string &Error, DiagnosticConsumer *DiagC, llvm::function_ref Callback) { // Always disable source location resolutions from .swiftsourceinfo file @@ -601,29 +602,23 @@ bool swift::ide::CompletionInstance::performOperation( // We don't need token list. Invocation.getLangOptions().CollectParsedToken = false; - if (EnableASTCaching) { - // Compute the signature of the invocation. - llvm::hash_code ArgsHash(0); - for (auto arg : Args) - ArgsHash = llvm::hash_combine(ArgsHash, StringRef(arg)); + // Compute the signature of the invocation. + llvm::hash_code ArgsHash(0); + for (auto arg : Args) + ArgsHash = llvm::hash_combine(ArgsHash, StringRef(arg)); - // Concurrent completions will block so that they have higher chance to use - // the cached completion instance. - std::lock_guard lock(mtx); + // Concurrent completions will block so that they have higher chance to use + // the cached completion instance. + std::lock_guard lock(mtx); - if (performCachedOperationIfPossible(Invocation, ArgsHash, FileSystem, - completionBuffer, Offset, DiagC, - Callback)) - return true; + if (performCachedOperationIfPossible(ArgsHash, FileSystem, completionBuffer, + Offset, DiagC, Callback)) { + return true; + } - if (performNewOperation(ArgsHash, Invocation, FileSystem, completionBuffer, - Offset, Error, DiagC, Callback)) - return true; - } else { - // Concurrent completions may happen in parallel when caching is disabled. - if (performNewOperation(None, Invocation, FileSystem, completionBuffer, - Offset, Error, DiagC, Callback)) - return true; + if(performNewOperation(ArgsHash, Invocation, FileSystem, completionBuffer, + Offset, Error, DiagC, Callback)) { + return true; } assert(!Error.empty()); diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift b/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift index 6b86cc98a88e5..96fe52c196f58 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_avoid_check.swift @@ -40,7 +40,7 @@ func foo() { // RUN: -shell -- cp -R $INPUT_DIR/ClangFW.framework_mod/* %t/Frameworks/ClangFW.framework/ == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo '### Checking dependencies' == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift b/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift index 6b467da21c4a7..2ea30a5138254 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_bridged.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift b/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift index 543d7f3875ff1..ce3900873e445 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_clangmodule.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift b/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift index 61561efc3bdfe..83f2c76eb28af 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_otherfile.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift b/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift index 15233fed951b6..13d039936cc79 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_ownfile.swift @@ -46,7 +46,7 @@ func foo(val: MyStruct) { // RUN: cp %t/State1.swift %t/test.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:4 %t/test.swift -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift b/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift index 2ed5cfbe3c6ec..6235a5b808a3a 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_swiftmodule.swift @@ -29,7 +29,7 @@ func foo() { // RUN: %target-swift-frontend -emit-module -module-name SwiftFW -o %t/Frameworks/SwiftFW.framework/Modules/SwiftFW.swiftmodule/%target-swiftmodule-name $INPUT_DIR/SwiftFW_src/Funcs.swift // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=5:3 %s -- ${COMPILER_ARGS[@]} == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift index 84753c3a8c3f2..af0831df7cb87 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift @@ -12,7 +12,7 @@ func foo(value: MyStruct) { // RUN: cp %S/Inputs/checkdeps/MyProject/LibraryExt.swift %t/VFS/ // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift b/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift index 1a8916dc0aceb..ec5bd8edbe5dd 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_vfs_open.swift @@ -12,7 +12,7 @@ func foo(value: MyStruct) { // RUN: cp %S/Inputs/checkdeps/MyProject/LibraryExt.swift %t/VFS/ // RUN: %sourcekitd-test \ -// RUN: -req=global-config -completion-check-dependency-interval ${DEPCHECK_INTERVAL} == \ +// RUN: -req=global-config -req-opts=completion_check_dependency_interval=${DEPCHECK_INTERVAL} == \ // RUN: -shell -- echo "### Initial" == \ // RUN: -req=complete.open -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ diff --git a/test/SourceKit/CodeComplete/complete_sequence.swift b/test/SourceKit/CodeComplete/complete_sequence.swift index d65a1c24b55f2..3ad76768e4253 100644 --- a/test/SourceKit/CodeComplete/complete_sequence.swift +++ b/test/SourceKit/CodeComplete/complete_sequence.swift @@ -19,8 +19,9 @@ func bar(arg: Bar) { // Disabled. // RUN: %sourcekitd-test \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -- %s > %t.response +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 ==\ +// RUN: -req=complete -pos=12:11 %s -- %s == \ +// RUN: -req=complete -pos=15:11 %s -- %s > %t.response // RUN: %FileCheck --check-prefix=RESULT_SLOW %s < %t.response // Enabled. diff --git a/test/SourceKit/CodeComplete/complete_sequence_race.swift b/test/SourceKit/CodeComplete/complete_sequence_race.swift index 191ee53a15080..2876e239ca437 100644 --- a/test/SourceKit/CodeComplete/complete_sequence_race.swift +++ b/test/SourceKit/CodeComplete/complete_sequence_race.swift @@ -19,21 +19,23 @@ func bar(arg: Bar) { // ReuseASTContext disabled. // RUN: %sourcekitd-test \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=17:1 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=17:1 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=12:11 %s -async -- %s == \ -// RUN: -req=complete -req-opts=reuseastcontext=0 -pos=15:11 %s -async -- %s +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=17:1 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s == \ +// RUN: -req=complete -pos=17:1 %s -async -- %s == \ +// RUN: -req=complete -pos=12:11 %s -async -- %s == \ +// RUN: -req=complete -pos=15:11 %s -async -- %s // ReuseASTContext enabled. // RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=5 \ // RUN: -req=complete -pos=12:11 %s -async -- %s == \ // RUN: -req=complete -pos=15:11 %s -async -- %s == \ // RUN: -req=complete -pos=12:11 %s -async -- %s == \ diff --git a/test/SourceKit/CodeComplete/complete_without_stdlib.swift b/test/SourceKit/CodeComplete/complete_without_stdlib.swift index 88d792388173a..7ece49f8f6aa4 100644 --- a/test/SourceKit/CodeComplete/complete_without_stdlib.swift +++ b/test/SourceKit/CodeComplete/complete_without_stdlib.swift @@ -10,10 +10,11 @@ class Str { // RUN: %empty-directory(%t/sdk) // RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 \ // RUN: -req=complete -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk | %FileCheck %s // RUN: %sourcekitd-test \ -// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk == \ -// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk | %FileCheck %s +// RUN: -req=complete -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk == \ +// RUN: -req=complete -pos=4:1 %s -- %s -resource-dir %t/rsrc -sdk %t/sdk | %FileCheck %s // CHECK: key.results: [ // CHECK-NOT: key.description: diff --git a/test/SourceKit/ConformingMethods/basic.swift b/test/SourceKit/ConformingMethods/basic.swift index 35701bdefb7dc..551c53336ab90 100644 --- a/test/SourceKit/ConformingMethods/basic.swift +++ b/test/SourceKit/ConformingMethods/basic.swift @@ -26,9 +26,12 @@ func testing(obj: C) { let _ = obj. } -// RUN: %sourcekitd-test -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD' -- -module-name MyModule %s > %t.response +// RUN: %sourcekitd-test \ +// RUN: -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD' -- -module-name MyModule %s > %t.response // RUN: %diff -u %s.response %t.response -// RUN: %sourcekitd-test -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD',reuseastcontext=0 -- -module-name MyModule %s | %FileCheck %s --check-prefix=DISABLED +// RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 == \ +// RUN: -req=conformingmethods -pos=26:14 -repeat-request=2 %s -req-opts=expectedtypes='$s8MyModule7Target2PD;$s8MyModule7Target1PD' -- -module-name MyModule %s | %FileCheck %s --check-prefix=DISABLED // DISABLED-NOT: key.reuseastcontext // DISABLED: key.members: [ diff --git a/test/SourceKit/CursorInfo/use-swift-source-info.swift b/test/SourceKit/CursorInfo/use-swift-source-info.swift index 05a391ee5c8b6..6130411f17a47 100644 --- a/test/SourceKit/CursorInfo/use-swift-source-info.swift +++ b/test/SourceKit/CursorInfo/use-swift-source-info.swift @@ -12,10 +12,10 @@ func bar() { // RUN: %target-swift-frontend -enable-batch-mode -emit-module -emit-module-doc -emit-module-path %t/Foo.swiftmodule %t/Foo.swift -module-name Foo -emit-module-source-info-path %t/Foo.swiftsourceinfo -emit-module-doc-path %t/Foo.swiftdoc // // Test setting optimize for ide to false -// RUN: %sourcekitd-test -req=global-config -for-ide=0 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITH %s +// RUN: %sourcekitd-test -req=global-config -req-opts=optimize_for_ide=0 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITH %s // // Test setting optimize for ide to true -// RUN: %sourcekitd-test -req=global-config -for-ide=1 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITHOUT %s +// RUN: %sourcekitd-test -req=global-config -req-opts=optimize_for_ide=1 == -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITHOUT %s // // Test sourcekitd-test's default global configuration request (optimize for ide is true) // RUN: %sourcekitd-test -req=cursor -pos=3:3 %s -- -I %t -target %target-triple %s | %FileCheck --check-prefixes=BOTH,WITHOUT %s diff --git a/test/SourceKit/TypeContextInfo/typecontext_basic.swift b/test/SourceKit/TypeContextInfo/typecontext_basic.swift index def196cd861c4..0eda3237abd2a 100644 --- a/test/SourceKit/TypeContextInfo/typecontext_basic.swift +++ b/test/SourceKit/TypeContextInfo/typecontext_basic.swift @@ -25,9 +25,12 @@ func test(obj: C) { let _ = obj.foo(x: } -// RUN: %sourcekitd-test -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -- %s > %t.response +// RUN: %sourcekitd-test \ +// RUN: -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -- %s > %t.response // RUN: %diff -u %s.response %t.response -// RUN: %sourcekitd-test -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -req-opts=reuseastcontext=0 -- %s | %FileCheck %s --check-prefix=DISABLED +// RUN: %sourcekitd-test \ +// RUN: -req=global-config -req-opts=completion_max_astcontext_reuse_count=0 == \ +// RUN: -req=typecontextinfo -repeat-request=2 -pos=25:22 %s -- %s | %FileCheck %s --check-prefix=DISABLED // DISABLED-NOT: key.reuseastcontext // DISABLED: key.results: [ diff --git a/tools/SourceKit/include/SourceKit/Core/Context.h b/tools/SourceKit/include/SourceKit/Core/Context.h index 922c1ab5c3c21..da9f19027b5a2 100644 --- a/tools/SourceKit/include/SourceKit/Core/Context.h +++ b/tools/SourceKit/include/SourceKit/Core/Context.h @@ -31,14 +31,20 @@ namespace SourceKit { class GlobalConfig { public: struct Settings { - /// When true, the default compiler options and other configuration flags will be chosen to optimize for - /// usage from an IDE. + /// When true, the default compiler options and other configuration flags + /// will be chosen to optimize for usage from an IDE. /// /// At the time of writing this just means ignoring .swiftsourceinfo files. bool OptimizeForIDE = false; - /// Interval second for checking dependencies in fast code completion. - unsigned CompletionCheckDependencyInterval = 5; + struct CompletionOptions { + + /// Max count of reusing ASTContext for cached code completion. + unsigned MaxASTContextReuseCount = 100; + + /// Interval second for checking dependencies in cached code completion. + unsigned CheckDependencyInterval = 5; + } CompletionOpts; }; private: @@ -47,9 +53,10 @@ class GlobalConfig { public: Settings update(Optional OptimizeForIDE, + Optional CompletionMaxASTContextReuseCount, Optional CompletionCheckDependencyInterval); bool shouldOptimizeForIDE() const; - unsigned getCompletionCheckDependencyInterval() const; + Settings::CompletionOptions getCompletionOpts() const; }; class Context { diff --git a/tools/SourceKit/lib/Core/Context.cpp b/tools/SourceKit/lib/Core/Context.cpp index b7899db03ba6c..f73c3fed54b55 100644 --- a/tools/SourceKit/lib/Core/Context.cpp +++ b/tools/SourceKit/lib/Core/Context.cpp @@ -18,12 +18,17 @@ using namespace SourceKit; GlobalConfig::Settings GlobalConfig::update(Optional OptimizeForIDE, + Optional CompletionMaxASTContextReuseCount, Optional CompletionCheckDependencyInterval) { llvm::sys::ScopedLock L(Mtx); if (OptimizeForIDE.hasValue()) State.OptimizeForIDE = *OptimizeForIDE; + if (CompletionMaxASTContextReuseCount.hasValue()) + State.CompletionOpts.MaxASTContextReuseCount = + *CompletionMaxASTContextReuseCount; if (CompletionCheckDependencyInterval.hasValue()) - State.CompletionCheckDependencyInterval = *CompletionCheckDependencyInterval; + State.CompletionOpts.CheckDependencyInterval = + *CompletionCheckDependencyInterval; return State; }; @@ -31,9 +36,10 @@ bool GlobalConfig::shouldOptimizeForIDE() const { llvm::sys::ScopedLock L(Mtx); return State.OptimizeForIDE; } -unsigned GlobalConfig::getCompletionCheckDependencyInterval() const { +GlobalConfig::Settings::CompletionOptions +GlobalConfig::getCompletionOpts() const { llvm::sys::ScopedLock L(Mtx); - return State.CompletionCheckDependencyInterval; + return State.CompletionOpts; } SourceKit::Context::Context( diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h index f8f1d03225a2b..5ed52659a083e 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.h @@ -42,7 +42,6 @@ struct Options { bool hideLowPriority = true; bool hideByNameStyle = true; bool fuzzyMatching = true; - bool reuseASTContextIfPossible = true; bool annotatedDescription = false; unsigned minFuzzyLength = 2; unsigned showTopNonLiteralResults = 3; diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index 06d3a912d4b51..8e8e9bf8bbb95 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -121,9 +121,9 @@ static bool swiftCodeCompleteImpl( unsigned Offset, SwiftCodeCompletionConsumer &SwiftConsumer, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, bool annotateDescription, std::string &Error) { + bool annotateDescription, std::string &Error) { return Lang.performCompletionLikeOperation( - UnresolvedInputFile, Offset, Args, FileSystem, EnableASTCaching, Error, + UnresolvedInputFile, Offset, Args, FileSystem, Error, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a factory for code completion callbacks that will feed the // Consumer. @@ -215,7 +215,6 @@ void SwiftLangSupport::codeComplete( std::string Error; if (!swiftCodeCompleteImpl(*this, UnresolvedInputFile, Offset, SwiftConsumer, Args, fileSystem, - CCOpts.reuseASTContextIfPossible, CCOpts.annotatedDescription, Error)) { SKConsumer.failed(Error); } @@ -734,7 +733,6 @@ static void translateCodeCompletionOptions(OptionsDictionary &from, static UIdent KeyContextWeight("key.codecomplete.sort.contextweight"); static UIdent KeyFuzzyWeight("key.codecomplete.sort.fuzzyweight"); static UIdent KeyPopularityBonus("key.codecomplete.sort.popularitybonus"); - static UIdent KeyReuseASTContext("key.codecomplete.reuseastcontext"); static UIdent KeyAnnotatedDescription("key.codecomplete.annotateddescription"); from.valueForOption(KeySortByName, to.sortByName); @@ -760,7 +758,6 @@ static void translateCodeCompletionOptions(OptionsDictionary &from, from.valueForOption(KeyPopularityBonus, to.popularityBonus); from.valueForOption(KeyHideByName, to.hideByNameStyle); from.valueForOption(KeyTopNonLiteral, to.showTopNonLiteralResults); - from.valueForOption(KeyReuseASTContext, to.reuseASTContextIfPossible); from.valueForOption(KeyAnnotatedDescription, to.annotatedDescription); } @@ -1032,7 +1029,6 @@ static void transformAndForwardResults( std::string error; if (!swiftCodeCompleteImpl(lang, buffer.get(), str.size(), swiftConsumer, cargs, session->getFileSystem(), - options.reuseASTContextIfPossible, options.annotatedDescription, error)) { consumer.failed(error); return; @@ -1134,7 +1130,6 @@ void SwiftLangSupport::codeCompleteOpen( // Invoke completion. if (!swiftCodeCompleteImpl(*this, inputBuf, offset, swiftConsumer, extendedArgs, fileSystem, - CCOpts.reuseASTContextIfPossible, CCOpts.annotatedDescription, error)) { consumer.failed(error); return; diff --git a/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp b/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp index f2814e606baf0..176f307dd14bd 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp @@ -26,11 +26,10 @@ using namespace SourceKit; using namespace swift; using namespace ide; -static void translateConformingMethodListOptions(OptionsDictionary &from, - ConformingMethodList::Options &to) { - static UIdent KeyReuseASTContext("key.conformingmethods.reuseastcontext"); - - from.valueForOption(KeyReuseASTContext, to.reuseASTContextIfPossible); +static void +translateConformingMethodListOptions(OptionsDictionary &from, + ConformingMethodList::Options &to) { + // ConformingMethodList doesn't receive any options at this point. } static bool swiftConformingMethodListImpl( @@ -39,9 +38,9 @@ static bool swiftConformingMethodListImpl( ArrayRef ExpectedTypeNames, ide::ConformingMethodListConsumer &Consumer, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error) { + std::string &Error) { return Lang.performCompletionLikeOperation( - UnresolvedInputFile, Offset, Args, FileSystem, EnableASTCaching, Error, + UnresolvedInputFile, Offset, Args, FileSystem, Error, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a factory for code completion callbacks that will feed the // Consumer. @@ -194,7 +193,7 @@ void SwiftLangSupport::getConformingMethodList( if (!swiftConformingMethodListImpl(*this, UnresolvedInputFile, Offset, Args, ExpectedTypeNames, Consumer, fileSystem, - options.reuseASTContextIfPossible, error)) { + error)) { SKConsumer.failed(error); } } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp index 14e267b21477e..02b066e70ee6e 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp @@ -264,8 +264,11 @@ class InMemoryFileSystemProvider: public SourceKit::FileSystemProvider { static void configureCompletionInstance(std::shared_ptr CompletionInst, std::shared_ptr GlobalConfig) { - CompletionInst->setDependencyCheckIntervalSecond( - GlobalConfig->getCompletionCheckDependencyInterval()); + auto Opts = GlobalConfig->getCompletionOpts(); + CompletionInst->setOptions({ + Opts.MaxASTContextReuseCount, + Opts.CheckDependencyInterval + }); } SwiftLangSupport::SwiftLangSupport(SourceKit::Context &SKCtx) @@ -986,7 +989,7 @@ bool SwiftLangSupport::performCompletionLikeOperation( llvm::MemoryBuffer *UnresolvedInputFile, unsigned Offset, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error, + std::string &Error, llvm::function_ref Callback) { assert(FileSystem); @@ -1042,8 +1045,7 @@ bool SwiftLangSupport::performCompletionLikeOperation( return CompletionInst->performOperation(Invocation, Args, FileSystem, newBuffer.get(), Offset, - EnableASTCaching, Error, - &CIDiags, Callback); + Error, &CIDiags, Callback); } CloseClangModuleFiles::~CloseClangModuleFiles() { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h index f64adc35c85d6..81f61f49c7759 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h @@ -222,13 +222,13 @@ class SessionCacheMap { namespace TypeContextInfo { struct Options { - bool reuseASTContextIfPossible = true; + // TypeContextInfo doesn't receive any options at this point. }; } // namespace TypeContextInfo namespace ConformingMethodList { struct Options { - bool reuseASTContextIfPossible = true; + // ConformingMethodList doesn't receive any options at this point. }; } // namespace ConformingMethodList @@ -465,7 +465,7 @@ class SwiftLangSupport : public LangSupport { llvm::MemoryBuffer *UnresolvedInputFile, unsigned Offset, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error, + std::string &Error, llvm::function_ref Callback); //==========================================================================// diff --git a/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp index 5a7b8bdd3dcad..9e857ba8ac506 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp @@ -27,9 +27,7 @@ using namespace ide; static void translateTypeContextInfoOptions(OptionsDictionary &from, TypeContextInfo::Options &to) { - static UIdent KeyReuseASTContext("key.typecontextinfo.reuseastcontext"); - - from.valueForOption(KeyReuseASTContext, to.reuseASTContextIfPossible); + // TypeContextInfo doesn't receive any options at this point. } static bool swiftTypeContextInfoImpl( @@ -37,9 +35,9 @@ static bool swiftTypeContextInfoImpl( unsigned Offset, ide::TypeContextInfoConsumer &Consumer, ArrayRef Args, llvm::IntrusiveRefCntPtr FileSystem, - bool EnableASTCaching, std::string &Error) { + std::string &Error) { return Lang.performCompletionLikeOperation( - UnresolvedInputFile, Offset, Args, FileSystem, EnableASTCaching, Error, + UnresolvedInputFile, Offset, Args, FileSystem, Error, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a factory for code completion callbacks that will feed the // Consumer. @@ -168,8 +166,7 @@ void SwiftLangSupport::getExpressionContextInfo( } Consumer(SKConsumer); if (!swiftTypeContextInfoImpl(*this, UnresolvedInputFile, Offset, Consumer, - Args, fileSystem, - options.reuseASTContextIfPossible, error)) { + Args, fileSystem, error)) { SKConsumer.failed(error); } } diff --git a/tools/SourceKit/tools/sourcekitd-test/Options.td b/tools/SourceKit/tools/sourcekitd-test/Options.td index 5119a2e169470..522cc38fbecee 100644 --- a/tools/SourceKit/tools/sourcekitd-test/Options.td +++ b/tools/SourceKit/tools/sourcekitd-test/Options.td @@ -140,14 +140,6 @@ def vfs_files : CommaJoined<["-"], "vfs-files=">, def vfs_name : Separate<["-"], "vfs-name">, HelpText<"Specify a virtual filesystem name">; -def optimize_for_ide : Joined<["-"], "for-ide=">, - HelpText<"Value for the OptimizeForIde global configuration setting">; - -def completion_check_dependency_interval : Separate<["-"], "completion-check-dependency-interval">, - HelpText<"Inteval seconds for checking dependencies in fast completion">; -def completion_check_dependency_interval_EQ : Joined<["-"], "completion-check-dependency-interval=">, - Alias; - def suppress_config_request : Flag<["-"], "suppress-config-request">, HelpText<"Suppress the default global configuration request, that is otherwise sent before any other request (except for the global-config request itself)">; diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp index ee577379698a8..7b49e636d0933 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp @@ -371,29 +371,6 @@ bool TestOptions::parseArgs(llvm::ArrayRef Args) { VFSName = InputArg->getValue(); break; - case OPT_optimize_for_ide: { - bool Value; - if (StringRef(InputArg->getValue()).getAsInteger(10, Value)) { - llvm::errs() << "error: expected 0 or 1 for 'for-ide'\n"; - return true; - } - OptimizeForIde = Value; - break; - } - - case OPT_completion_check_dependency_interval: { - int64_t Value; - if (StringRef(InputArg->getValue()).getAsInteger(10, Value)) { - llvm::errs() << "error: expected number for inteval\n"; - return true; - } else if (Value < 0) { - llvm::errs() << "error: completion-check-dependency-interval must be > 0\n"; - return true; - } - CompletionCheckDependencyInterval = Value; - break; - } - case OPT_suppress_config_request: SuppressDefaultConfigRequest = true; break; diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index b9f2b3eaf373b..925fea4e93638 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -538,15 +538,17 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { case SourceKitRequest::GlobalConfiguration: sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestGlobalConfiguration); - if (Opts.OptimizeForIde.hasValue()) - sourcekitd_request_dictionary_set_int64( - Req, KeyOptimizeForIDE, - static_cast(Opts.OptimizeForIde.getValue())); - if (Opts.CompletionCheckDependencyInterval.hasValue()) - sourcekitd_request_dictionary_set_int64( - Req, KeyCompletionCheckDependencyInterval, - static_cast( - Opts.CompletionCheckDependencyInterval.getValue())); + + for (auto &Opt : Opts.RequestOptions) { + auto KeyValue = StringRef(Opt).split('='); + std::string KeyStr("key."); + KeyStr.append(KeyValue.first.str()); + sourcekitd_uid_t Key = sourcekitd_uid_get_from_cstr(KeyStr.c_str()); + + int64_t Value = 0; + KeyValue.second.getAsInteger(0, Value); + sourcekitd_request_dictionary_set_int64(Req, Key, Value); + } break; case SourceKitRequest::ProtocolVersion: diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp index 42f632ef79194..d95425de1bd4b 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp @@ -437,23 +437,27 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) { ResponseBuilder RB; auto dict = RB.getDictionary(); - Optional OptimizeForIDE; - int64_t EditorMode = true; - if (!Req.getInt64(KeyOptimizeForIDE, EditorMode, true)) { - OptimizeForIDE = EditorMode; - } + Optional OptimizeForIDE = + Req.getOptionalInt64(KeyOptimizeForIDE) + .map([](int64_t v) -> bool { return v; }); + Optional CompletionMaxASTContextReuseCount = + Req.getOptionalInt64(KeyCompletionMaxASTContextReuseCount) + .map([](int64_t v) -> unsigned { return v; }); Optional CompletionCheckDependencyInterval = - Req.getOptionalInt64(KeyCompletionCheckDependencyInterval) - .map([](int64_t v)->unsigned{return v;}); + Req.getOptionalInt64(KeyCompletionCheckDependencyInterval) + .map([](int64_t v) -> unsigned { return v; }); - GlobalConfig::Settings UpdatedConfig = Config->update( - OptimizeForIDE, CompletionCheckDependencyInterval); + GlobalConfig::Settings UpdatedConfig = + Config->update(OptimizeForIDE, CompletionMaxASTContextReuseCount, + CompletionCheckDependencyInterval); getGlobalContext().getSwiftLangSupport().globalConfigurationUpdated(Config); dict.set(KeyOptimizeForIDE, UpdatedConfig.OptimizeForIDE); + dict.set(KeyCompletionMaxASTContextReuseCount, + UpdatedConfig.CompletionOpts.MaxASTContextReuseCount); dict.set(KeyCompletionCheckDependencyInterval, - UpdatedConfig.CompletionCheckDependencyInterval); + UpdatedConfig.CompletionOpts.CheckDependencyInterval); return Rec(RB.createResponse()); } diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 691318b4885db..a17fba4f13646 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -829,7 +829,7 @@ static bool doCodeCompletionImpl( CompletionInstance CompletionInst; auto isSuccess = CompletionInst.performOperation( Invocation, /*Args=*/{}, llvm::vfs::getRealFileSystem(), CleanFile.get(), - Offset, /*EnableASTCaching=*/false, Error, + Offset, Error, CodeCompletionDiagnostics ? &PrintDiags : nullptr, [&](CompilerInstance &CI, bool reusingASTContext) { assert(!reusingASTContext && "reusing AST context without enabling it"); @@ -1207,8 +1207,7 @@ static int doBatchCodeCompletion(const CompilerInvocation &InitInvok, bool wasASTContextReused = false; bool isSuccess = CompletionInst.performOperation( Invocation, /*Args=*/{}, FileSystem, completionBuffer.get(), Offset, - /*EnableASTCaching=*/true, Error, - CodeCompletionDiagnostics ? &PrintDiags : nullptr, + Error, CodeCompletionDiagnostics ? &PrintDiags : nullptr, [&](CompilerInstance &CI, bool reusingASTContext) { // Create a CodeCompletionConsumer. std::unique_ptr Consumer( diff --git a/utils/gyb_sourcekit_support/UIDs.py b/utils/gyb_sourcekit_support/UIDs.py index e8d1eb947b3c6..41b5dab310480 100644 --- a/utils/gyb_sourcekit_support/UIDs.py +++ b/utils/gyb_sourcekit_support/UIDs.py @@ -181,6 +181,8 @@ def __init__(self, internal_name, external_name): KEY('OptimizeForIDE', 'key.optimize_for_ide'), KEY('RequiredBystanders', 'key.required_bystanders'), KEY('ReusingASTContext', 'key.reusingastcontext'), + KEY('CompletionMaxASTContextReuseCount', + 'key.completion_max_astcontext_reuse_count'), KEY('CompletionCheckDependencyInterval', 'key.completion_check_dependency_interval'), KEY('AnnotatedTypename', 'key.annotated.typename'), From fab497a02e37029d44f9c70bbbb81940c8694cf1 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 3 Sep 2020 12:19:51 -0700 Subject: [PATCH 570/663] [Localization] Use testing fixture in DefToYAMLConverter Makes it easy to setup convertion from def-to-yaml and remove a temporary file. --- .../Localization/DefToYAMLConverterTests.cpp | 96 +++++++++++-------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/unittests/Localization/DefToYAMLConverterTests.cpp b/unittests/Localization/DefToYAMLConverterTests.cpp index c7d5f47bfd6af..19ad8cef98b4e 100644 --- a/unittests/Localization/DefToYAMLConverterTests.cpp +++ b/unittests/Localization/DefToYAMLConverterTests.cpp @@ -11,9 +11,11 @@ //===----------------------------------------------------------------------===// #include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ToolOutputFile.h" @@ -35,37 +37,75 @@ enum LocalDiagID : uint32_t { NumDiags }; +static constexpr const char *const diagnosticID[] = { +#define DIAG(KIND, ID, Options, Text, Signature) #ID, +#include "swift/AST/DiagnosticsAll.def" +}; + static constexpr const char *const diagnosticMessages[] = { #define DIAG(KIND, ID, Options, Text, Signature) Text, #include "swift/AST/DiagnosticsAll.def" }; static std::string getMainExecutablePath() { - std::string libPath = llvm::sys::path::parent_path(SWIFTLIB_DIR); + llvm::StringRef libPath = llvm::sys::path::parent_path(SWIFTLIB_DIR); llvm::SmallString<128> MainExecutablePath(libPath); llvm::sys::path::remove_filename(MainExecutablePath); // Remove /lib llvm::sys::path::remove_filename(MainExecutablePath); // Remove /. - return std::string(MainExecutablePath.str()); + return std::string(MainExecutablePath); } static std::string getDefaultLocalizationPath() { llvm::SmallString<128> DefaultDiagnosticMessagesDir(getMainExecutablePath()); llvm::sys::path::append(DefaultDiagnosticMessagesDir, "share", "swift", "diagnostics"); - return std::string(DefaultDiagnosticMessagesDir.str()); + return std::string(DefaultDiagnosticMessagesDir); } -static std::string getDefToYAMLConverterPath() { - llvm::SmallString<128> defYAMLConverter(getMainExecutablePath()); - llvm::sys::path::append(defYAMLConverter, "bin", - "swift-def-to-yaml-converter"); - return std::string(defYAMLConverter.str()); -} +struct DefToYAMLConverterTest : public ::testing::Test { + std::string YAMLPath; + +public: + DefToYAMLConverterTest() { + llvm::SmallString<128> tempFilename; + std::error_code error = + llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); + assert(!error); + + YAMLPath = std::string(tempFilename); + } + + void SetUp() override { + bool failed = convertDefIntoYAML(YAMLPath); + assert(!failed && "failed to generate a YAML file"); + } + + void TearDown() override { llvm::sys::fs::remove(YAMLPath); } + + /// Random number in [0,n) + unsigned RandNumber(unsigned n) { return unsigned(rand()) % n; } -/// Random number in [0,n) -unsigned randNum(unsigned n) { return unsigned(rand()) % n; } +protected: + static bool convertDefIntoYAML(std::string outputPath) { + std::error_code error; + llvm::raw_fd_ostream OS(outputPath, error, llvm::sys::fs::F_None); + if (OS.has_error() || error) + return true; -TEST(DefToYAMLConverterTest, missingLocalizationFiles) { + llvm::ArrayRef ids(diagnosticID, LocalDiagID::NumDiags); + llvm::ArrayRef messages(diagnosticMessages, + LocalDiagID::NumDiags); + + DefToYAMLConverter converter(ids, messages); + converter.convert(OS); + + OS.flush(); + + return OS.has_error(); + } +}; + +TEST_F(DefToYAMLConverterTest, MissingLocalizationFiles) { ASSERT_TRUE(llvm::sys::fs::exists(getDefaultLocalizationPath())); llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); llvm::sys::path::append(EnglishLocalization, "en"); @@ -75,45 +115,23 @@ TEST(DefToYAMLConverterTest, missingLocalizationFiles) { ASSERT_TRUE(llvm::sys::fs::exists(EnglishLocalization)); } -TEST(DefToYAMLConverterTest, matchDiagnosticMessagesSequentially) { - llvm::SmallString<128> defYAMLConverter(getDefToYAMLConverterPath()); - defYAMLConverter.append(" --output-filename="); - - llvm::SmallString<128> tempFilename; - std::error_code EC = - llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); - ASSERT_FALSE(EC); - llvm::sys::RemoveFileOnSignal(tempFilename); - defYAMLConverter.append(tempFilename); - std::system(defYAMLConverter.c_str()); - - YAMLLocalizationProducer yaml(tempFilename.str()); +TEST_F(DefToYAMLConverterTest, MatchDiagnosticMessagesSequentially) { + YAMLLocalizationProducer yaml(YAMLPath); yaml.forEachAvailable([](swift::DiagID id, llvm::StringRef translation) { llvm::StringRef msg = diagnosticMessages[static_cast(id)]; ASSERT_EQ(msg, translation); }); } -TEST(DefToYAMLConverterTest, matchDiagnosticMessagesRandomly) { - llvm::SmallString<128> defYAMLConverter(getDefToYAMLConverterPath()); - defYAMLConverter.append(" --output-filename="); - - llvm::SmallString<128> tempFilename; - std::error_code EC = - llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); - ASSERT_FALSE(EC); - llvm::sys::RemoveFileOnSignal(tempFilename); - defYAMLConverter.append(tempFilename); - std::system(defYAMLConverter.c_str()); - - YAMLLocalizationProducer yaml(tempFilename.str()); +TEST_F(DefToYAMLConverterTest, MatchDiagnosticMessagesRandomly) { + YAMLLocalizationProducer yaml(YAMLPath); std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<> distr(50, LocalDiagID::NumDiags); unsigned numberOfQueries = distr(gen); while (numberOfQueries--) { - unsigned randomNum = randNum(LocalDiagID::NumDiags); + unsigned randomNum = RandNumber(LocalDiagID::NumDiags); DiagID randomId = static_cast(randomNum); llvm::StringRef msg = diagnosticMessages[randomNum]; llvm::StringRef translation = yaml.getMessageOr(randomId, ""); From 1d72ec9badc9e2ea4bc5ff2511f1104239ab3777 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Thu, 3 Sep 2020 20:18:52 -0700 Subject: [PATCH 571/663] [AutoDiff] NFC: improve debug logging. (#33793) Print value/instruction with context in non-differentiability error debug log. --- include/swift/SILOptimizer/Differentiation/ADContext.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/swift/SILOptimizer/Differentiation/ADContext.h b/include/swift/SILOptimizer/Differentiation/ADContext.h index 368d7fc8d4aec..4e8fd61a9f143 100644 --- a/include/swift/SILOptimizer/Differentiation/ADContext.h +++ b/include/swift/SILOptimizer/Differentiation/ADContext.h @@ -273,7 +273,8 @@ ADContext::emitNondifferentiabilityError(SILValue value, Diag diag, U &&... args) { LLVM_DEBUG({ getADDebugStream() << "Diagnosing non-differentiability.\n"; - getADDebugStream() << "For value:\n" << value; + auto &s = getADDebugStream() << "For value:\n"; + value->printInContext(s); getADDebugStream() << "With invoker:\n" << invoker << '\n'; }); // If instruction does not have a valid location, use the function location @@ -290,7 +291,8 @@ ADContext::emitNondifferentiabilityError(SILInstruction *inst, Diag diag, U &&... args) { LLVM_DEBUG({ getADDebugStream() << "Diagnosing non-differentiability.\n"; - getADDebugStream() << "For instruction:\n" << *inst; + auto &s = getADDebugStream() << "For instruction:\n"; + inst->printInContext(s); getADDebugStream() << "With invoker:\n" << invoker << '\n'; }); // If instruction does not have a valid location, use the function location From 29f2f7719a6a499c0fa6b17e05b9bd9777ef2897 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 3 Sep 2020 23:53:34 -0700 Subject: [PATCH 572/663] [docs] Update branching documentation to use new release branch naming scheme. (#33766) --- docs/Branches.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/Branches.md b/docs/Branches.md index 083f89610419d..036849f9da2a1 100644 --- a/docs/Branches.md +++ b/docs/Branches.md @@ -18,11 +18,11 @@ To switch from one set of branches to another, you can use `utils/update-checkou ## The Release Branches -| Swift | LLVM Project -| ---------------- | ---------------------- -| swift-x.y-branch | swift/swift-x.y-branch +| Swift | LLVM Project +| ----------- | ----------------- +| release/x.y | swift/release/x.y -At some point before a release, a *release branch* will be created in every repository with a name like `swift-4.0-branch`. (The actual number is chosen by Apple.) After the branch has been created, commits must make it to this branch to make it into the release. In some cases, the [release manager][] for the branch will decide to merge in all additional changes from `master`; otherwise, cherry-picking changes and making a new pull request is the way to go. If there are any "patch" releases (e.g. Swift 4.0.1), they will also come from this branch. +At some point before a release, a *release branch* will be created in every repository with a name like `release/5.3`. (The actual number is chosen by Apple.) After the branch has been created, commits must make it to this branch to make it into the release. In some cases, the [release manager][] for the branch will decide to merge in all additional changes from `master`; otherwise, cherry-picking changes and making a new pull request is the way to go. If there are any "patch" releases (e.g. Swift 5.3.1), they will also come from this branch. Note that these branches come not from the "development" branches (above), but the "upstream" branches (below). This is because they need to contain the latest changes not just from Swift, but from the LLVM project as well. For some releases, the release branch for the LLVM project will be timed to coincide with the corresponding llvm.org release branch. @@ -35,7 +35,7 @@ Note that these branches come not from the "development" branches (above), but t `swift/master-next` is a branch for LLVM that includes all changes necessary to support Swift. Changes from llvm.org's master branch are automatically merged in. Why isn't this just `swift/master`? Well, because LLVM changes *very* rapidly, and that wouldn't be very stable. However, we do want to make sure the Swift stuff keeps working. -If you are making changes to LLVM to support Swift, you'll probably need to work on them in `swift/master` to test them against Swift itself, but they should be committed to `swift/master-next`, and cherry-picked to the current release branch (`swift/swift-x.y-branch`) if needed. Remember, the release branches are automerged into `swift/master` on a regular basis. +If you are making changes to LLVM to support Swift, you'll probably need to work on them in `swift/master` to test them against Swift itself, but they should be committed to `swift/master-next`, and cherry-picked to the current release branch (`swift/release/x.y`) if needed. Remember, the release branches are automerged into `swift/master` on a regular basis. (If you're making changes to LLVM Project that *aren't* about Swift, they should generally be made on llvm.org instead, then cherry-picked to the active release branch or `swift/master`.) @@ -83,6 +83,6 @@ Some branches are *automerged* into other branches, to keep them in sync. This i - `master` is automerged into `master-next` ### LLVM Project -- `swift/swift-x.y-branch` (the *latest* release branch) is automerged into `swift/master` +- `swift/release/x.y` (the *latest* release branch) is automerged into `swift/master` - llvm.org's `master` is automerged into `swift/master-next` -- llvm.org's release branch *may* be automerged into `swift/swift-x.y-branch`, if they are in sync +- llvm.org's release branch *may* be automerged into `swift/release/x.y`, if they are in sync From 9d908ec4dce789f6c542d5467ddea41b2b0cd9b5 Mon Sep 17 00:00:00 2001 From: Valeriy Van Date: Fri, 4 Sep 2020 18:13:25 +0200 Subject: [PATCH 573/663] [stdlib] Removes redundant buffer zeroing in IndexPath initialiser by using `init(unsafeUninitializedCapacity:initializingWith:) (#31122) * Remove redundant buffer zeroing in IndexPath initializer * Use switch instead of multibranch if * Rename buf back into buffer to make diff clearer --- stdlib/public/Darwin/Foundation/IndexPath.swift | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/stdlib/public/Darwin/Foundation/IndexPath.swift b/stdlib/public/Darwin/Foundation/IndexPath.swift index 62b29064ab5a6..5c5d89d4ed702 100644 --- a/stdlib/public/Darwin/Foundation/IndexPath.swift +++ b/stdlib/public/Darwin/Foundation/IndexPath.swift @@ -617,16 +617,17 @@ public struct IndexPath : ReferenceConvertible, Equatable, Hashable, MutableColl fileprivate init(nsIndexPath: __shared ReferenceType) { let count = nsIndexPath.length - if count == 0 { + switch count { + case 0: _indexes = [] - } else if count == 1 { + case 1: _indexes = .single(nsIndexPath.index(atPosition: 0)) - } else if count == 2 { + case 2: _indexes = .pair(nsIndexPath.index(atPosition: 0), nsIndexPath.index(atPosition: 1)) - } else { - var indexes = Array(repeating: 0, count: count) - indexes.withUnsafeMutableBufferPointer { (buffer: inout UnsafeMutableBufferPointer) -> Void in + default: + let indexes = Array(unsafeUninitializedCapacity: count) { buffer, initializedCount in nsIndexPath.getIndexes(buffer.baseAddress!, range: NSRange(location: 0, length: count)) + initializedCount = count } _indexes = .array(indexes) } From 115b53f0912317e003226d6831c564b57f33327b Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Fri, 4 Sep 2020 09:16:21 -0700 Subject: [PATCH 574/663] Punctuation --- docs/DynamicCasting.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md index 466666b7173b2..0efc4fcb862b8 100644 --- a/docs/DynamicCasting.md +++ b/docs/DynamicCasting.md @@ -355,9 +355,9 @@ Implementation Note: `AnyObject` is represented in memory as a pointer to a refc ### Error (SE-0112) -The Error type behaves like an ordinary existential type for casting purposes. +The `Error` type behaves like an ordinary existential type for casting purposes. -(See "Note: 'Self-conforming' protocols" below for additional details relevant to the Error protocol.) +(See "Note: 'Self-conforming' protocols" below for additional details relevant to the `Error` protocol.) ### AnyHashable (SE-0131) @@ -377,7 +377,7 @@ protocol P {} ``` As a result of this definition, there is an existential type (also called `P`). -This existential type is also known as a "protocol witness" type since it exposes exactly the capabilities that are defined by the protocol. +This existential type is also known as a "protocol witness type" since it exposes exactly the capabilities that are defined by the protocol. Other capabilities of the type `T` are not accessible from a `P` instance. Any Swift instance of a concrete type `T` can be cast to the type `P` iff `T` conforms to the protocol `P`. From aa20633f4e2b1f440f2d9ae11cacfa7e4993cdca Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Fri, 4 Sep 2020 10:23:47 -0700 Subject: [PATCH 575/663] [AutoDiff] [Sema] Fix missing access-level mismatch diagnostic in `-enable-testing` builds. (#33800) When a derivative function is internal and its original function is public, there should be an error when the derivative is not `@usableFromInline`. This patch fixes a bug where the error does not appear in SwiftPM debug build configurations (or any configurations with `-enable-testing`). `ValueDecl::getEffectiveAccess()` should not be used when we perform formal access checking for AutoDiff-related declaration attributes because it will treat all internal declarations as public when `-enable-testing` is enabled. Instea we should use a combination of `ValueDecl::getFormalAccess()` and `ValueDecl::isUsableFromInline()`. Also, add a `RUN` line with `-enable-testing` to all AutoDiff declaration attribute test files. Resolves SR-13500 (rdar://68336300). --- lib/Sema/TypeCheckAttr.cpp | 3 ++- test/AutoDiff/Sema/derivative_attr_type_checking.swift | 1 + test/AutoDiff/Sema/differentiable_attr_type_checking.swift | 1 + test/AutoDiff/Sema/transpose_attr_type_checking.swift | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index df4080e85a1ba..f929b00bccf9f 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -4645,7 +4645,8 @@ static bool typeCheckDerivativeAttr(ASTContext &Ctx, Decl *D, if (originalAFD->getFormalAccess() == derivative->getFormalAccess()) return true; return originalAFD->getFormalAccess() == AccessLevel::Public && - derivative->getEffectiveAccess() == AccessLevel::Public; + (derivative->getFormalAccess() == AccessLevel::Public || + derivative->isUsableFromInline()); }; // Check access level compatibility for original and derivative functions. diff --git a/test/AutoDiff/Sema/derivative_attr_type_checking.swift b/test/AutoDiff/Sema/derivative_attr_type_checking.swift index 598dc3600879a..451bf4dd4fb51 100644 --- a/test/AutoDiff/Sema/derivative_attr_type_checking.swift +++ b/test/AutoDiff/Sema/derivative_attr_type_checking.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %s +// RUN: %target-swift-frontend-typecheck -enable-testing -verify -disable-availability-checking %s // Swift.AdditiveArithmetic:3:17: note: cannot yet register derivative default implementation for protocol requirements diff --git a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift index a14090d14fe52..ac54b0bc349ed 100644 --- a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift +++ b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %s +// RUN: %target-swift-frontend-typecheck -enable-testing -verify -disable-availability-checking %s import _Differentiation diff --git a/test/AutoDiff/Sema/transpose_attr_type_checking.swift b/test/AutoDiff/Sema/transpose_attr_type_checking.swift index a49ff941a49d3..513e0b3d83ab9 100644 --- a/test/AutoDiff/Sema/transpose_attr_type_checking.swift +++ b/test/AutoDiff/Sema/transpose_attr_type_checking.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend-typecheck -verify %s +// RUN: %target-swift-frontend-typecheck -enable-testing -verify %s import _Differentiation From 65a547c4e62da29af82a661dbd2930728618e050 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Fri, 4 Sep 2020 13:39:40 -0400 Subject: [PATCH 576/663] [benchmark] Add new benchmark for floating-point conversion --- benchmark/CMakeLists.txt | 1 + .../FloatingPointConversion.swift | 66 +++++++++++++++++++ benchmark/utils/main.swift | 2 + 3 files changed, 69 insertions(+) create mode 100644 benchmark/single-source/FloatingPointConversion.swift diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 1f0f58171f4d7..f63860100e928 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -91,6 +91,7 @@ set(SWIFT_BENCH_MODULES single-source/Fibonacci single-source/FindStringNaive single-source/FlattenList + single-source/FloatingPointConversion single-source/FloatingPointParsing single-source/FloatingPointPrinting single-source/Hanoi diff --git a/benchmark/single-source/FloatingPointConversion.swift b/benchmark/single-source/FloatingPointConversion.swift new file mode 100644 index 0000000000000..e85efd0526a1d --- /dev/null +++ b/benchmark/single-source/FloatingPointConversion.swift @@ -0,0 +1,66 @@ +//===--- FloatingPointConversion.swift ------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let FloatingPointConversion = [ + BenchmarkInfo( + name: "ConvertFloatingPoint.ConcreteDoubleToDouble", + runFunction: run_ConvertFloatingPoint_ConcreteDoubleToDouble, + tags: [.validation, .api]), + BenchmarkInfo( + name: "ConvertFloatingPoint.GenericDoubleToDouble", + runFunction: run_ConvertFloatingPoint_GenericDoubleToDouble, + tags: [.validation, .api]), +] + +let doubles = [ + 1.8547832857295, 26.321549267719135, 98.9544480962058, 73.70286973782363, + 82.04918555938816, 76.38902969312758, 46.35647857011161, 64.0821426030317, + 97.82373347320156, 55.742361037720634, 23.677941665488856, 93.7347588108058, + 80.72657040828412, 32.137580733275826, 64.78192587530002, 21.459686568896863, + 24.88407660280718, 85.25905561999171, 12.858847331083556, 29.418845887252864, + 67.64627066438761, 68.09883494078815, 57.781587230862094, 63.38335631088038, + 83.31376661495327, 87.45936846358906, 0.6757674136841918, 86.45465036820696, + 84.72715137492781, 82.67894289189142, 26.1667640621554, 21.24895661442493, + 65.06399183516027, 90.06549073883058, 59.2736650501005, 94.5800380563246, + 84.22617424003917, 26.93158630395639, 9.069952095976841, 96.10067836567679, + 62.60505762081415, 29.57878462599286, 66.06040114311294, 51.709999429326636, + 64.79777579583545, 45.25948795832151, 94.31492354198335, 52.31096166433902, +] + +@inline(__always) +func convert< + T: BinaryFloatingPoint, U: BinaryFloatingPoint +>(_ value: T, to: U.Type) -> U { + U(value) +} + +@inline(never) +public func run_ConvertFloatingPoint_ConcreteDoubleToDouble(_ N: Int) { + for _ in 0..<(N * 100) { + for element in doubles { + let f = Double(identity(element)) + blackHole(f) + } + } +} + +@inline(never) +public func run_ConvertFloatingPoint_GenericDoubleToDouble(_ N: Int) { + for _ in 0..<(N * 100) { + for element in doubles { + let f = convert(identity(element), to: Double.self) + blackHole(f) + } + } +} diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index aa3504ba35d72..160c4eb50c8a3 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -79,6 +79,7 @@ import ExistentialPerformance import Fibonacci import FindStringNaive import FlattenList +import FloatingPointConversion import FloatingPointParsing import FloatingPointPrinting import Hanoi @@ -266,6 +267,7 @@ registerBenchmark(Fibonacci) registerBenchmark(FindStringNaive) registerBenchmark(FlattenListLoop) registerBenchmark(FlattenListFlatMap) +registerBenchmark(FloatingPointConversion) registerBenchmark(FloatingPointParsing) registerBenchmark(FloatingPointPrinting) registerBenchmark(Hanoi) From 004bc07b133637c14926611c9dc966ffcf109573 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 4 Sep 2020 18:46:36 +0100 Subject: [PATCH 577/663] Fix `push_back` in `autolink_extract_main.cpp` --- tools/driver/autolink_extract_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/driver/autolink_extract_main.cpp b/tools/driver/autolink_extract_main.cpp index a9976ac021a50..39c338e239310 100644 --- a/tools/driver/autolink_extract_main.cpp +++ b/tools/driver/autolink_extract_main.cpp @@ -166,7 +166,7 @@ extractLinkerFlagsFromObjectFile(const llvm::object::WasmObjectFile *ObjectFile, SegmentData.split(SplitFlags, llvm::StringRef("\0", 1), -1, /*KeepEmpty=*/false); for (const auto &Flag : SplitFlags) - LinkerFlags.push_back(Flag); + LinkerFlags.push_back(Flag.str()); } } return false; From 42f79b0e87683d2d9224f01b87385381f91b5d16 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Fri, 4 Sep 2020 14:06:42 -0400 Subject: [PATCH 578/663] [stdlib] Make use of protocol requirements to convert from concrete types --- stdlib/public/core/FloatingPoint.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/stdlib/public/core/FloatingPoint.swift b/stdlib/public/core/FloatingPoint.swift index fa7ce591f6530..c0f60afd2446e 100644 --- a/stdlib/public/core/FloatingPoint.swift +++ b/stdlib/public/core/FloatingPoint.swift @@ -1890,7 +1890,18 @@ extension BinaryFloatingPoint { /// - Parameter value: A floating-point value to be converted. @inlinable public init(_ value: Source) { - self = Self._convert(from: value).value + switch value { + case let value_ as Float: + self = Self(value_) + case let value_ as Double: + self = Self(value_) +#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + case let value_ as Float80: + self = Self(value_) +#endif + default: + self = Self._convert(from: value).value + } } /// Creates a new instance from the given value, if it can be represented From 028a75572c72904ec4a89845182dd86ef5ca5086 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Fri, 4 Sep 2020 11:12:12 -0700 Subject: [PATCH 579/663] ModuleInterface: remark potential version differences between SDK and prebuilt modules Prebuilt-module directory now contains a SystemVersion.plist file copied from the SDK it's built from. This patch teaches the compiler to remark this version and the SDK version when -Rmodule-interface-rebuild is specified. The difference between these versions could help us debug unusable prebuilt modules. --- include/swift/AST/DiagnosticsFrontend.def | 3 ++ include/swift/Basic/Platform.h | 7 +++ include/swift/IDE/Utils.h | 4 -- lib/Basic/Platform.cpp | 44 +++++++++++++++++++ lib/Frontend/ModuleInterfaceLoader.cpp | 14 ++++-- lib/IDE/Utils.cpp | 41 +---------------- .../ModuleCache/Inputs/sdk-build-ver.1.plist | 6 +++ .../ModuleCache/Inputs/sdk-build-ver.2.plist | 6 +++ .../out-of-date-forwarding-module.swift | 5 +++ .../swift-api-digester/swift-api-digester.cpp | 3 +- 10 files changed, 85 insertions(+), 48 deletions(-) create mode 100644 test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.1.plist create mode 100644 test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.2.plist diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 11ed4e6906297..8a4a0aaa98c71 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -366,6 +366,9 @@ ERROR(error_extracting_flags_from_module_interface,none, "error extracting flags from module interface", ()) REMARK(rebuilding_module_from_interface,none, "rebuilding module '%0' from interface '%1'", (StringRef, StringRef)) +NOTE(sdk_version_pbm_version,none, + "SDK build version is '%0'; prebuilt modules were " + "built using SDK build version: '%1'", (StringRef, StringRef)) NOTE(out_of_date_module_here,none, "%select{compiled|cached|forwarding|prebuilt}0 module is out of date: '%1'", (unsigned, StringRef)) diff --git a/include/swift/Basic/Platform.h b/include/swift/Basic/Platform.h index 3585c6ab6e7c1..a5f13d915883b 100644 --- a/include/swift/Basic/Platform.h +++ b/include/swift/Basic/Platform.h @@ -106,6 +106,13 @@ namespace swift { /// Retrieve the target SDK version for the given SDKInfo and target triple. llvm::VersionTuple getTargetSDKVersion(clang::driver::DarwinSDKInfo &SDKInfo, const llvm::Triple &triple); + + /// Get SDK build version. + std::string getSDKBuildVersion(StringRef SDKPath); + std::string getSDKBuildVersionFromPlist(StringRef Path); + + /// Get SDK name. + std::string getSDKName(StringRef SDKPath); } // end namespace swift #endif // SWIFT_BASIC_PLATFORM_H diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 8eaf34a69b5e7..c916f7742bb22 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -101,10 +101,6 @@ void walkOverriddenDecls(const ValueDecl *VD, void collectModuleNames(StringRef SDKPath, std::vector &Modules); -std::string getSDKName(StringRef Path); - -std::string getSDKVersion(StringRef Path); - struct PlaceholderOccurrence { /// The complete placeholder string. StringRef FullPlaceholder; diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index 62add579df745..ad1db82c717cf 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -473,3 +473,47 @@ swift::getTargetSDKVersion(clang::driver::DarwinSDKInfo &SDKInfo, return SDKVersion; } + +static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) { + auto BufOrErr = llvm::MemoryBuffer::getFile(Path); + if (!BufOrErr) { + // FIXME: diagnose properly + return {}; + } + + std::string Key = ""; + Key += KeyName; + Key += ""; + + StringRef Lines = BufOrErr.get()->getBuffer(); + while (!Lines.empty()) { + StringRef CurLine; + std::tie(CurLine, Lines) = Lines.split('\n'); + if (CurLine.find(Key) != StringRef::npos) { + std::tie(CurLine, Lines) = Lines.split('\n'); + unsigned Begin = CurLine.find("") + strlen(""); + unsigned End = CurLine.find(""); + return CurLine.substr(Begin, End - Begin).str(); + } + } + + return {}; +} + +std::string swift::getSDKBuildVersionFromPlist(StringRef Path) { + return getPlistEntry(Path, "ProductBuildVersion"); +} + +std::string swift::getSDKBuildVersion(StringRef Path) { + return getSDKBuildVersionFromPlist((llvm::Twine(Path) + + "/System/Library/CoreServices/SystemVersion.plist").str()); +} + +std::string swift::getSDKName(StringRef Path) { + std::string Name = getPlistEntry(llvm::Twine(Path)+"/SDKSettings.plist", + "CanonicalName"); + if (Name.empty() && Path.endswith(".sdk")) { + Name = llvm::sys::path::filename(Path).drop_back(strlen(".sdk")).str(); + } + return Name; +} diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 508fc3fc38234..1f2df7b25a0c8 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -286,10 +286,18 @@ struct ModuleRebuildInfo { /// Emits a diagnostic for all out-of-date compiled or forwarding modules /// encountered while trying to load a module. void diagnose(ASTContext &ctx, SourceLoc loc, StringRef moduleName, - StringRef interfacePath) { + StringRef interfacePath, StringRef prebuiltCacheDir) { ctx.Diags.diagnose(loc, diag::rebuilding_module_from_interface, moduleName, interfacePath); - + auto SDKVer = getSDKBuildVersion(ctx.SearchPathOpts.SDKPath); + llvm::SmallString<64> buffer = prebuiltCacheDir; + llvm::sys::path::append(buffer, "SystemVersion.plist"); + auto PBMVer = getSDKBuildVersionFromPlist(buffer.str()); + if (!SDKVer.empty() && !PBMVer.empty()) { + // Remark the potential version difference. + ctx.Diags.diagnose(loc, diag::sdk_version_pbm_version, SDKVer, + PBMVer); + } // We may have found multiple failing modules, that failed for different // reasons. Emit a note for each of them. for (auto &mod : outOfDateModules) { @@ -911,7 +919,7 @@ class ModuleInterfaceLoaderImpl { // Diagnose that we didn't find a loadable module, if we were asked to. auto remarkRebuild = [&]() { rebuildInfo.diagnose(ctx, diagnosticLoc, moduleName, - interfacePath); + interfacePath, prebuiltCacheDir); }; // If we found an out-of-date .swiftmodule, we still want to add it as // a dependency of the .swiftinterface. That way if it's updated, but diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index e333f666cfa9c..0ee903e76caea 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -13,6 +13,7 @@ #include "swift/IDE/Utils.h" #include "swift/Basic/Edit.h" #include "swift/Basic/SourceManager.h" +#include "swift/Basic/Platform.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Driver/FrontendUtil.h" #include "swift/Frontend/Frontend.h" @@ -664,46 +665,6 @@ ide::replacePlaceholders(std::unique_ptr InputBuf, }); } -static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) { - auto BufOrErr = llvm::MemoryBuffer::getFile(Path); - if (!BufOrErr) { - llvm::errs() << "could not open '" << Path << "': " << BufOrErr.getError().message() << '\n'; - return {}; - } - - std::string Key = ""; - Key += KeyName; - Key += ""; - - StringRef Lines = BufOrErr.get()->getBuffer(); - while (!Lines.empty()) { - StringRef CurLine; - std::tie(CurLine, Lines) = Lines.split('\n'); - if (CurLine.find(Key) != StringRef::npos) { - std::tie(CurLine, Lines) = Lines.split('\n'); - unsigned Begin = CurLine.find("") + strlen(""); - unsigned End = CurLine.find(""); - return CurLine.substr(Begin, End - Begin).str(); - } - } - - return {}; -} - -std::string ide::getSDKName(StringRef Path) { - std::string Name = getPlistEntry(llvm::Twine(Path)+"/SDKSettings.plist", - "CanonicalName"); - if (Name.empty() && Path.endswith(".sdk")) { - Name = llvm::sys::path::filename(Path).drop_back(strlen(".sdk")).str(); - } - return Name; -} - -std::string ide::getSDKVersion(StringRef Path) { - return getPlistEntry(llvm::Twine(Path)+"/System/Library/CoreServices/" - "SystemVersion.plist", "ProductBuildVersion"); -} - // Modules failing to load are commented-out. static const char *OSXModuleList[] = { "AGL", diff --git a/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.1.plist b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.1.plist new file mode 100644 index 0000000000000..a7775b7bc9349 --- /dev/null +++ b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.1.plist @@ -0,0 +1,6 @@ + + + ProductBuildVersion + 11111 + + diff --git a/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.2.plist b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.2.plist new file mode 100644 index 0000000000000..bfe4278c694dc --- /dev/null +++ b/test/ModuleInterface/ModuleCache/Inputs/sdk-build-ver.2.plist @@ -0,0 +1,6 @@ + + + ProductBuildVersion + 22222 + + diff --git a/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift b/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift index 680dbb1ddd648..269314d8d0f9d 100644 --- a/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift +++ b/test/ModuleInterface/ModuleCache/RebuildRemarks/out-of-date-forwarding-module.swift @@ -1,6 +1,10 @@ // RUN: %empty-directory(%t/ModuleCache) // RUN: %empty-directory(%t/Build) // RUN: %empty-directory(%t/PrebuiltCache) +// RUN: %empty-directory(%t/System/Library/CoreServices) + +// RUN: cp %S/../Inputs/sdk-build-ver.1.plist %t/System/Library/CoreServices/SystemVersion.plist +// RUN: cp %S/../Inputs/sdk-build-ver.2.plist %t/PrebuiltCache/SystemVersion.plist // 1. Create a dummy module // RUN: echo 'public func publicFunction() {}' > %t/TestModule.swift @@ -30,3 +34,4 @@ import TestModule // expected-remark {{rebuilding module 'TestModule' from inter // expected-note @-2 {{dependency is out of date}} // expected-note @-3 {{prebuilt module is out of date}} // expected-note @-4 {{dependency is out of date}} +// expected-note @-5 {{SDK build version is '11111'; prebuilt modules were built using SDK build version: '22222'}} diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index ae18abbb35373..e5820cae73a3d 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -26,6 +26,7 @@ // can be reflected as source-breaking changes for API users. If they are, // the output of api-digester will include such changes. +#include "swift/Basic/Platform.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" #include "swift/Frontend/SerializedDiagnosticConsumer.h" #include "swift/AST/DiagnosticsModuleDiffer.h" @@ -2704,7 +2705,7 @@ static CheckerOptions getCheckOpts(int argc, char *argv[]) { Opts.ToolArgs.push_back(argv[i]); if (!options::SDK.empty()) { - auto Ver = getSDKVersion(options::SDK); + auto Ver = getSDKBuildVersion(options::SDK); if (!Ver.empty()) { Opts.ToolArgs.push_back("-sdk-version"); Opts.ToolArgs.push_back(Ver); From 514dce144ff44b9ea18abea1477873d66eacac1b Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Fri, 4 Sep 2020 15:02:38 -0400 Subject: [PATCH 580/663] Update copyright year on benchmark and its template --- benchmark/scripts/Template.swift | 4 ++-- benchmark/single-source/FloatingPointConversion.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmark/scripts/Template.swift b/benchmark/scripts/Template.swift index 00337a1fb48b4..ea25b249d4679 100644 --- a/benchmark/scripts/Template.swift +++ b/benchmark/scripts/Template.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -19,4 +19,4 @@ public let {name} = [ @inline(never) public func run_{name}(N: Int) {{ // TODO -}} \ No newline at end of file +}} diff --git a/benchmark/single-source/FloatingPointConversion.swift b/benchmark/single-source/FloatingPointConversion.swift index e85efd0526a1d..ef67b2d31c4b5 100644 --- a/benchmark/single-source/FloatingPointConversion.swift +++ b/benchmark/single-source/FloatingPointConversion.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information From e920b702492fc991eeb2ba100b4ed2f54fe5c178 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Fri, 4 Sep 2020 12:34:58 -0700 Subject: [PATCH 581/663] [Test] Disable Sanitizers/symbolication.swift for now --- test/Sanitizers/symbolication.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/Sanitizers/symbolication.swift b/test/Sanitizers/symbolication.swift index 89f3335cfd6c2..2fc6ea7cb94ba 100644 --- a/test/Sanitizers/symbolication.swift +++ b/test/Sanitizers/symbolication.swift @@ -5,6 +5,8 @@ // REQUIRES: asan_runtime // REQUIRES: VENDOR=apple +// REQUIRES: rdar68353068 + // Check that Sanitizer reports are properly symbolicated on Apple platforms, // both out-of-process (via `atos`) and when falling back to in-process // symbolication. Note that `atos` also demangles Swift symbol names. From 0310a701d91ed34d8b3a50a915b16e9eb4117fb8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 15:19:40 -0400 Subject: [PATCH 582/663] AST: Remove EnableASTScope flag and force it to always be on --- include/swift/AST/ASTScope.h | 5 +- include/swift/Basic/LangOptions.h | 13 -- include/swift/Frontend/Frontend.h | 5 - include/swift/Option/FrontendOptions.td | 3 - include/swift/Option/Options.td | 8 - lib/AST/ASTScopeCreation.cpp | 2 - lib/AST/UnqualifiedLookup.cpp | 163 ------------------ lib/Driver/ToolChains.cpp | 2 - lib/Frontend/CompilerInvocation.cpp | 7 - lib/Sema/TypeCheckStmt.cpp | 32 +--- lib/Sema/TypeChecker.cpp | 5 +- ...ubscript-generic-conjuction-astscope.swift | 4 +- test/NameLookup/warn-if-astscope.swift | 13 -- test/Parse/toplevel_library_invalid.swift | 1 - test/SILGen/local_recursion.swift | 1 - test/lit.cfg | 4 - 16 files changed, 12 insertions(+), 256 deletions(-) delete mode 100644 test/NameLookup/warn-if-astscope.swift diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 0cac9c8e61277..2f3588ec3f92c 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -44,11 +44,10 @@ /// try disabling it. /// \p message must be a string literal #define ASTScopeAssert(predicate, message) \ - assert((predicate) && message \ - " Try compiling with '-disable-astscope-lookup'.") + assert((predicate) && message) #define ASTScope_unreachable(message) \ - llvm_unreachable(message " Try compiling with '-disable-astscope-lookup'.") + llvm_unreachable(message) namespace swift { diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 557714ae6bf0b..a05d65611801b 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -248,25 +248,12 @@ namespace swift { /// This is a staging flag; eventually it will be removed. bool EnableDeserializationRecovery = true; - /// Should we use \c ASTScope-based resolution for unqualified name lookup? - /// Default is in \c ParseLangArgs - /// - /// This is a staging flag; eventually it will be removed. - bool EnableASTScopeLookup = true; - /// Someday, ASTScopeLookup will supplant lookup in the parser bool DisableParserLookup = false; - /// Should we compare to ASTScope-based resolution for debugging? - bool CrosscheckUnqualifiedLookup = false; - /// Should we stress ASTScope-based resolution for debugging? bool StressASTScopeLookup = false; - /// Since some tests fail if the warning is output, use a flag to decide - /// whether it is. The warning is useful for testing. - bool WarnIfASTScopeLookup = false; - /// Build the ASTScope tree lazily bool LazyASTScopes = true; diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index c33e9ee9f46fa..0fa9e0ee1344e 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -328,11 +328,6 @@ class CompilerInvocation { return CodeCompletionOffset != ~0U; } - /// Called from lldb, see rdar://53971116 - void disableASTScopeLookup() { - LangOpts.EnableASTScopeLookup = false; - } - /// Retrieve a module hash string that is suitable for uniquely /// identifying the conditions under which the module was built, for use /// in generating a cached PCH file for the bridging header. diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index c55ca598baff7..82d904206c720 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -160,9 +160,6 @@ def crosscheck_unqualified_lookup : Flag<["-"], "crosscheck-unqualified-lookup"> def stress_astscope_lookup : Flag<["-"], "stress-astscope-lookup">, HelpText<"Stress ASTScope-based unqualified name lookup (for testing)">; -def warn_if_astscope_lookup : Flag<["-"], "warn-if-astscope-lookup">, - HelpText<"Print a warning if ASTScope lookup is used">; - def lazy_astscopes : Flag<["-"], "lazy-astscopes">, HelpText<"Build ASTScopes lazily">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 8273359fcb97c..9c255ec001058 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1107,14 +1107,6 @@ def scan_clang_dependencies : Flag<["-"], "scan-clang-dependencies">, HelpText<"Scan dependencies of the given Clang module">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; -def enable_astscope_lookup : Flag<["-"], "enable-astscope-lookup">, - Flags<[FrontendOption]>, - HelpText<"Enable ASTScope-based unqualified name lookup">; - -def disable_astscope_lookup : Flag<["-"], "disable-astscope-lookup">, - Flags<[FrontendOption]>, - HelpText<"Disable ASTScope-based unqualified name lookup">; - def disable_parser_lookup : Flag<["-"], "disable-parser-lookup">, Flags<[FrontendOption]>, HelpText<"Disable parser lookup & use ast scope lookup only (experimental)">; diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 4623e38970ea3..558287ddd458a 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1086,8 +1086,6 @@ void ASTScopeImpl::disownDescendants(ScopeCreator &scopeCreator) { ASTScopeImpl * ASTScopeImpl::expandAndBeCurrentDetectingRecursion(ScopeCreator &scopeCreator) { - assert(scopeCreator.getASTContext().LangOpts.EnableASTScopeLookup && - "Should not be getting here if ASTScopes are disabled"); return evaluateOrDefault(scopeCreator.getASTContext().evaluator, ExpandASTScopeRequest{this, &scopeCreator}, nullptr); } diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index a138f4528039e..3c573aad5a796 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -235,9 +235,6 @@ namespace { bool useASTScopesForLookup() const; - /// For testing, assume this lookup is enabled: - bool wouldUseASTScopesForLookupIfItWereEnabled() const; - void lookUpTopLevelNamesInModuleScopeContext(DeclContext *); void lookInASTScopes(); @@ -399,13 +396,6 @@ namespace { void print(raw_ostream &OS) const; void printResults(raw_ostream &OS) const; - bool verifyEqualTo(const UnqualifiedLookupFactory &&, StringRef thisLabel, - StringRef otherLabel) const; - - /// Legacy lookup is wrong here; we should NOT find this symbol. - bool shouldDiffer() const; - StringRef getSourceFileName() const; - #ifndef NDEBUG bool isTargetLookup() const; void stopForDebuggingIfStartingTargetLookup(bool isASTScopeLookup) const; @@ -497,14 +487,7 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUse{ DC, initialIsCascadingUse}; - const bool crosscheckUnqualifiedLookup = - Ctx.LangOpts.CrosscheckUnqualifiedLookup; if (useASTScopesForLookup()) { - static bool haveWarned = false; - if (!haveWarned && Ctx.LangOpts.WarnIfASTScopeLookup) { - haveWarned = true; - llvm::errs() << "WARNING: TRYING Scope exclusively\n"; - } lookInASTScopes(); } else { #ifndef NDEBUG @@ -516,28 +499,6 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { else lookupNamesIntroducedBy(contextAndIsCascadingUse, NULL); } - - if (crosscheckUnqualifiedLookup && - wouldUseASTScopesForLookupIfItWereEnabled()) { - ResultsVector results; - size_t indexOfFirstOuterResult = 0; - UnqualifiedLookupFactory altLookup(Name, DC, Loc, options, results, - indexOfFirstOuterResult); - if (!useASTScopesForLookup()) - altLookup.lookInASTScopes(); - else if (Name.isOperator()) - altLookup.lookupOperatorInDeclContexts(contextAndIsCascadingUse); - else - altLookup.lookupNamesIntroducedBy(contextAndIsCascadingUse, NULL); - - const auto *ASTScopeLabel = "ASTScope lookup"; - const auto *contextLabel = "context-bsed lookup"; - const auto *mainLabel = - useASTScopesForLookup() ? ASTScopeLabel : contextLabel; - const auto *alternateLabel = - useASTScopesForLookup() ? contextLabel : ASTScopeLabel; - assert(verifyEqualTo(std::move(altLookup), mainLabel, alternateLabel)); - } } void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext( @@ -562,12 +523,6 @@ void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext( } bool UnqualifiedLookupFactory::useASTScopesForLookup() const { - return Ctx.LangOpts.EnableASTScopeLookup && - wouldUseASTScopesForLookupIfItWereEnabled(); -} - -bool UnqualifiedLookupFactory::wouldUseASTScopesForLookupIfItWereEnabled() - const { if (!Loc.isValid()) return false; return (bool) DC->getParentSourceFile(); @@ -1335,124 +1290,6 @@ void UnqualifiedLookupFactory::print(raw_ostream &OS) const { OS << "\n"; } -#pragma mark debugging: output utilities for grepping - -static void writeLine(std::string s) { - llvm::errs() << "\n+-+-+-+- " << s << "\n"; -} - -StringRef UnqualifiedLookupFactory::getSourceFileName() const { - return DC->getParentSourceFile()->getFilename(); -} - -static void writeFirstLine(const UnqualifiedLookupFactory &ul, llvm::Twine s) { - std::string line = - std::string("In file: ") + ul.getSourceFileName().str() + ", " + s.str(); - writeLine(line); -} - -static void writeInconsistent(const UnqualifiedLookupFactory &me, - StringRef thisLabel, - const UnqualifiedLookupFactory &other, - StringRef otherLabel, llvm::Twine s) { - writeFirstLine(me, s); - other.print(llvm::errs()); - llvm::errs() << "\n" << thisLabel << " Results:\n"; - me.printResults(llvm::errs()); - llvm::errs() << "\n" << otherLabel << " Results:\n"; - other.printResults(llvm::errs()); - me.printScopes(llvm::errs()); -} - -#pragma mark comparing results - -bool UnqualifiedLookupFactory::verifyEqualTo( - const UnqualifiedLookupFactory &&other, const StringRef thisLabel, - StringRef otherLabel) const { - if (shouldDiffer()) { - return true; - } - auto writeErr = [&](llvm::Twine s) { - writeInconsistent(*this, thisLabel, other, otherLabel, s); - }; - if (Results.size() != other.Results.size()) { - writeErr(thisLabel + " found " + std::to_string(Results.size()) + " but " + - otherLabel + " found " + std::to_string(other.Results.size())); - assert(false && "mismatch in number of results"); - } - for (size_t i : indices(Results)) { - const auto &e = Results[i]; - const auto &oe = other.Results[i]; - if (e.getValueDecl() != oe.getValueDecl()) { - // print_ast_tc_function_bodies.swift generic from subscript vs get fn - std::string a; llvm::raw_string_ostream as(a); - std::string b; llvm::raw_string_ostream bs(b); - e.getValueDecl()->print(as); - oe.getValueDecl()->print(bs); - if (a == b) - llvm::errs() << "ValueDecls differ but print same\n"; - else { - writeErr(std::string( "ValueDecls differ at ") + std::to_string(i)); - assert(false && "other lookup found different Decl"); - } - } - if (e.getDeclContext() != oe.getDeclContext()) { - writeErr((std::string("Contexts differ at ")) + std::to_string(i)); - assert(false && "ASTScopeImpl found different context"); - } - // unsigned printContext(llvm::raw_ostream &OS, unsigned indent = 0, - // bool onlyAPartialLine = false) const; - } - if (IndexOfFirstOuterResult != other.IndexOfFirstOuterResult) { - writeErr( std::string("IndexOfFirstOuterResult differs, should be: ") - + std::to_string(IndexOfFirstOuterResult) - + std::string( ", is: ") - + std::to_string(other.IndexOfFirstOuterResult)); - assert(false && "other lookup IndexOfFirstOuterResult differs"); - } - if (recordedSF != other.recordedSF) { - writeErr(std::string("recordedSF differs: shouldBe: ") + - (recordedSF ? recordedSF->getFilename().str() - : std::string("")) + - std::string(" is: ") + - (other.recordedSF ? other.recordedSF->getFilename().str() - : std::string(""))); - assert(false && "other lookup recordedSF differs"); - } - if (recordedSF && recordedIsCascadingUse != other.recordedIsCascadingUse) { - writeErr(std::string("recordedIsCascadingUse differs: shouldBe: ") + - std::to_string(recordedIsCascadingUse) + std::string(" is: ") + - std::to_string(other.recordedIsCascadingUse)); - assert(false && "other lookup recordedIsCascadingUse differs"); - } - return true; -} - -bool UnqualifiedLookupFactory::shouldDiffer() const { - auto *SF = dyn_cast(DC->getModuleScopeContext()); - if (!SF) - return false; - - static std::vector testsThatShouldDiffer { - "swift/test/Constraints/diagnostics.swift", - "swift/test/Constraints/enum_cases.swift", - "swift/test/Constraints/rdar39401774.swift", - "swift/test/Constraints/rdar39401774-astscope.swift", - "swift/test/Interpreter/repl.swift", - "swift/test/Sema/diag_defer_captures.swift", - "swift/test/Sema/diag_use_before_declaration.swift", - "swift/test/SourceKit/CodeFormat/indent-closure.swift", - "swift/test/TypeCoercion/overload_noncall.swift", - "swift/test/expr/capture/nested_class.swift", - "swift/test/expr/capture/order.swift", - "swift/test/NameLookup/name_lookup2.swift" - }; - StringRef fileName = SF->getFilename(); - return llvm::any_of(testsThatShouldDiffer, [&](const char *testFile) { - return fileName.endswith(testFile); - }); -} - #pragma mark breakpointing #ifndef NDEBUG diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 7f669e54ba24c..87899830ea4b9 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -259,8 +259,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_debug_diagnostic_names); inputArgs.AddLastArg(arguments, options::OPT_print_educational_notes); inputArgs.AddLastArg(arguments, options::OPT_diagnostic_style); - inputArgs.AddLastArg(arguments, options::OPT_enable_astscope_lookup); - inputArgs.AddLastArg(arguments, options::OPT_disable_astscope_lookup); inputArgs.AddLastArg(arguments, options::OPT_disable_parser_lookup); inputArgs.AddLastArg(arguments, options::OPT_enable_experimental_concise_pound_file); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index cd7ed68196e2b..3f6468b95bad9 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -443,14 +443,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, } Opts.DisableParserLookup |= Args.hasArg(OPT_disable_parser_lookup); - Opts.EnableASTScopeLookup = - Args.hasFlag(options::OPT_enable_astscope_lookup, - options::OPT_disable_astscope_lookup, Opts.EnableASTScopeLookup) || - Opts.DisableParserLookup; - Opts.CrosscheckUnqualifiedLookup |= - Args.hasArg(OPT_crosscheck_unqualified_lookup); Opts.StressASTScopeLookup |= Args.hasArg(OPT_stress_astscope_lookup); - Opts.WarnIfASTScopeLookup |= Args.hasArg(OPT_warn_if_astscope_lookup); Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes); Opts.EnableNewOperatorLookup = Args.hasFlag(OPT_enable_new_operator_lookup, OPT_disable_new_operator_lookup, diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 1aec917a56eaf..2b7e8341006f4 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -303,11 +303,6 @@ static bool isDefer(DeclContext *dc) { /// same label. static void checkLabeledStmtShadowing( ASTContext &ctx, SourceFile *sourceFile, LabeledStmt *ls) { - // If ASTScope lookup is disabled, don't do this check at all. - // FIXME: Enable ASTScope lookup everywhere. - if (!ctx.LangOpts.EnableASTScopeLookup) - return; - auto name = ls->getLabelInfo().Name; if (name.empty() || !sourceFile || ls->getStartLoc().isInvalid()) return; @@ -411,13 +406,7 @@ static LabeledStmt *findBreakOrContinueStmtTarget( // FIXME: Once everything uses ASTScope lookup, \c oldActiveLabeledStmts // can go away. SmallVector activeLabeledStmts; - if (ctx.LangOpts.EnableASTScopeLookup) { - activeLabeledStmts = ASTScope::lookupLabeledStmts(sourceFile, loc); - } else { - activeLabeledStmts.insert( - activeLabeledStmts.end(), - oldActiveLabeledStmts.rbegin(), oldActiveLabeledStmts.rend()); - } + activeLabeledStmts = ASTScope::lookupLabeledStmts(sourceFile, loc); // Handle an unlabeled break separately; that's the easy case. if (targetName.empty()) { @@ -620,16 +609,11 @@ static bool checkFallthroughStmt( CaseStmt *fallthroughSource; CaseStmt *fallthroughDest; ASTContext &ctx = dc->getASTContext(); - if (ctx.LangOpts.EnableASTScopeLookup) { - auto sourceFile = dc->getParentSourceFile(); - std::tie(fallthroughSource, fallthroughDest) = - ASTScope::lookupFallthroughSourceAndDest(sourceFile, stmt->getLoc()); - assert(fallthroughSource == oldFallthroughSource); - assert(fallthroughDest == oldFallthroughDest); - } else { - fallthroughSource = oldFallthroughSource; - fallthroughDest = oldFallthroughDest; - } + auto sourceFile = dc->getParentSourceFile(); + std::tie(fallthroughSource, fallthroughDest) = + ASTScope::lookupFallthroughSourceAndDest(sourceFile, stmt->getLoc()); + assert(fallthroughSource == oldFallthroughSource); + assert(fallthroughDest == oldFallthroughDest); if (!fallthroughSource) { ctx.Diags.diagnose(stmt->getLoc(), diag::fallthrough_outside_switch); @@ -690,7 +674,6 @@ class StmtChecker : public StmtVisitor { // Verify that the ASTScope-based query for active labeled statements // is equivalent to what we have here. if (LS->getStartLoc().isValid() && sourceFile && - SC.getASTContext().LangOpts.EnableASTScopeLookup && !SC.getASTContext().Diags.hadAnyError() && !SC.LeaveBraceStmtBodyUnchecked) { // The labeled statements from ASTScope lookup have the @@ -2080,8 +2063,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator, // Typechecking, in particular ApplySolution is going to replace closures // with OpaqueValueExprs and then try to do lookups into the closures. // So, build out the body now. - if (ctx.LangOpts.EnableASTScopeLookup) - ASTScope::expandFunctionBody(AFD); + ASTScope::expandFunctionBody(AFD); // Type check the function body if needed. bool hadError = false; diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index f56b56339a4fa..9433f75177d5b 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -291,9 +291,8 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const { // scope-based lookups. Only the top-level scopes because extensions have not // been bound yet. auto &Ctx = SF->getASTContext(); - if (Ctx.LangOpts.EnableASTScopeLookup) - SF->getScope() - .buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); + SF->getScope() + .buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); BufferIndirectlyCausingDiagnosticRAII cpr(*SF); diff --git a/test/NameLookup/subscript-generic-conjuction-astscope.swift b/test/NameLookup/subscript-generic-conjuction-astscope.swift index 60cdc1991e46a..8fb1fc04f27bf 100644 --- a/test/NameLookup/subscript-generic-conjuction-astscope.swift +++ b/test/NameLookup/subscript-generic-conjuction-astscope.swift @@ -1,7 +1,5 @@ // Check that ASTScope lookup works for a construction found in GRDB's Row.swift -// RUN: %target-swift-frontend -typecheck %s -enable-astscope-lookup -warn-if-astscope-lookup 2>%t.out -// RUN: %FileCheck %s <%t.out -// CHECK: WARNING: TRYING Scope exclusively +// RUN: %target-swift-frontend -typecheck %s protocol P1 {} protocol P2 {} diff --git a/test/NameLookup/warn-if-astscope.swift b/test/NameLookup/warn-if-astscope.swift deleted file mode 100644 index f101cf0775033..0000000000000 --- a/test/NameLookup/warn-if-astscope.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Verify the action of -warn-if-astscope-lookup -// -// RUN: not %target-swift-frontend -typecheck %s -enable-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-WARN -// RUN: not %target-swift-frontend -typecheck %s -disable-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-WARN -// RUN: not %target-swift-frontend -typecheck %s -enable-astscope-lookup -warn-if-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-WARN -// RUN: not %target-swift-frontend -typecheck %s -disable-astscope-lookup -warn-if-astscope-lookup 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-WARN - -func foo() -> Int { - return bar() // create an error so the input to fileCheck isn't empty -} - -// CHECK-NO-WARN-NOT: WARNING: TRYING Scope exclusively -// CHECK-WARN: WARNING: TRYING Scope exclusively diff --git a/test/Parse/toplevel_library_invalid.swift b/test/Parse/toplevel_library_invalid.swift index 7b2eb68d5cdea..1206a42b422a4 100644 --- a/test/Parse/toplevel_library_invalid.swift +++ b/test/Parse/toplevel_library_invalid.swift @@ -1,5 +1,4 @@ // RUN: %target-typecheck-verify-swift -parse-as-library -// RUN: %target-typecheck-verify-swift -parse-as-library -enable-astscope-lookup let x = 42 x + x; // expected-error {{expressions are not allowed at the top level}} expected-warning {{result of operator '+' is unused}} diff --git a/test/SILGen/local_recursion.swift b/test/SILGen/local_recursion.swift index d408a4c983c93..09c83bda8220d 100644 --- a/test/SILGen/local_recursion.swift +++ b/test/SILGen/local_recursion.swift @@ -1,5 +1,4 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// RUN: %target-swift-emit-silgen -enable-astscope-lookup -parse-as-library %s | %FileCheck %s // CHECK-LABEL: sil hidden [ossa] @$s15local_recursionAA_1yySi_SitF : $@convention(thin) (Int, Int) -> () { // CHECK: bb0([[X:%0]] : $Int, [[Y:%1]] : $Int): diff --git a/test/lit.cfg b/test/lit.cfg index b35d22fdd150a..657adcf9ef88c 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -427,10 +427,6 @@ config.substitutions.append( ('%swift-syntax-test', config.swift_syntax_test) ) if 'syntax_parser_lib' in config.available_features: config.substitutions.append( ('%swift-syntax-parser-test', config.swift_syntax_parser_test) ) # For testing on CI -if '-enable-astscope-lookup' in config.swift_test_options: - config.available_features.add("enable-astscope-lookup") -if '-disable-astscope-lookup' in config.swift_test_options: - config.available_features.add("disable-astscope-lookup") if '-disable-parser-lookup' in config.swift_test_options: config.available_features.add("disable-parser-lookup") config.substitutions.append( ('%swift-indent', config.swift_indent) ) From 4a6280074d1f82ac211d24e18c76d90000432d55 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 3 Sep 2020 16:05:30 -0400 Subject: [PATCH 583/663] Sema: Remove old pre-ASTScope logic from TypeCheckStmt.cpp --- lib/Sema/TypeCheckStmt.cpp | 135 +++++++------------------------------ 1 file changed, 26 insertions(+), 109 deletions(-) diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 2b7e8341006f4..bf905c923c64c 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -399,12 +399,9 @@ static LabeledStmt *findUnlabeledBreakOrContinueStmtTarget( static LabeledStmt *findBreakOrContinueStmtTarget( ASTContext &ctx, SourceFile *sourceFile, SourceLoc loc, Identifier targetName, SourceLoc targetLoc, - bool isContinue, DeclContext *dc, - ArrayRef oldActiveLabeledStmts) { + bool isContinue, DeclContext *dc) { // Retrieve the active set of labeled statements. - // FIXME: Once everything uses ASTScope lookup, \c oldActiveLabeledStmts - // can go away. SmallVector activeLabeledStmts; activeLabeledStmts = ASTScope::lookupLabeledStmts(sourceFile, loc); @@ -603,17 +600,13 @@ static void checkFallthroughPatternBindingsAndTypes( /// Check the correctness of a 'fallthrough' statement. /// /// \returns true if an error occurred. -static bool checkFallthroughStmt( - DeclContext *dc, FallthroughStmt *stmt, - CaseStmt *oldFallthroughSource, CaseStmt *oldFallthroughDest) { +static bool checkFallthroughStmt(DeclContext *dc, FallthroughStmt *stmt) { CaseStmt *fallthroughSource; CaseStmt *fallthroughDest; ASTContext &ctx = dc->getASTContext(); auto sourceFile = dc->getParentSourceFile(); std::tie(fallthroughSource, fallthroughDest) = ASTScope::lookupFallthroughSourceAndDest(sourceFile, stmt->getLoc()); - assert(fallthroughSource == oldFallthroughSource); - assert(fallthroughDest == oldFallthroughDest); if (!fallthroughSource) { ctx.Diags.diagnose(stmt->getLoc(), diag::fallthrough_outside_switch); @@ -639,88 +632,11 @@ class StmtChecker : public StmtVisitor { /// DC - This is the current DeclContext. DeclContext *DC; - // Scope information for control flow statements - // (break, continue, fallthrough). - - /// The level of loop nesting. 'break' and 'continue' are valid only in scopes - /// where this is greater than one. - /// FIXME: Only required because EnableASTScopeLookup can be false - SmallVector ActiveLabeledStmts; - - /// The destination block for a 'fallthrough' statement. Null if the switch - /// scope depth is zero or if we are checking the final 'case' of the current - /// switch. - /// FIXME: Only required because EnableASTScopeLookup can be false - CaseStmt /*nullable*/ *FallthroughSource = nullptr; - CaseStmt /*nullable*/ *FallthroughDest = nullptr; - /// Skip type checking any elements inside 'BraceStmt', also this is /// propagated to ConstraintSystem. bool LeaveBraceStmtBodyUnchecked = false; ASTContext &getASTContext() const { return Ctx; }; - - struct AddLabeledStmt { - StmtChecker &SC; - AddLabeledStmt(StmtChecker &SC, LabeledStmt *LS) : SC(SC) { - // Verify that we don't have label shadowing. - auto sourceFile = SC.DC->getParentSourceFile(); - checkLabeledStmtShadowing(SC.getASTContext(), sourceFile, LS); - - // In any case, remember that we're in this labeled statement so that - // break and continue are aware of it. - SC.ActiveLabeledStmts.push_back(LS); - - // Verify that the ASTScope-based query for active labeled statements - // is equivalent to what we have here. - if (LS->getStartLoc().isValid() && sourceFile && - !SC.getASTContext().Diags.hadAnyError() && - !SC.LeaveBraceStmtBodyUnchecked) { - // The labeled statements from ASTScope lookup have the - // innermost labeled statement first, so reverse it to - // match the data structure maintained here. - auto activeFromASTScope = ASTScope::lookupLabeledStmts( - sourceFile, LS->getStartLoc()); - assert(activeFromASTScope.front() == LS); - std::reverse(activeFromASTScope.begin(), activeFromASTScope.end()); - if (activeFromASTScope != SC.ActiveLabeledStmts) { - llvm::errs() << "Old: "; - llvm::interleave(SC.ActiveLabeledStmts, [&](LabeledStmt *LS) { - llvm::errs() << LS; - }, [&] { - llvm::errs() << ' '; - }); - llvm::errs() << "\nNew: "; - llvm::interleave(activeFromASTScope, [&](LabeledStmt *LS) { - llvm::errs() << LS; - }, [&] { - llvm::errs() << ' '; - }); - llvm::errs() << "\n"; - } - assert(activeFromASTScope == SC.ActiveLabeledStmts); - } - } - ~AddLabeledStmt() { - SC.ActiveLabeledStmts.pop_back(); - } - }; - - struct AddSwitchNest { - StmtChecker &SC; - CaseStmt *OuterFallthroughSource; - CaseStmt *OuterFallthroughDest; - AddSwitchNest(StmtChecker &SC) - : SC(SC), - OuterFallthroughSource(SC.FallthroughSource), - OuterFallthroughDest(SC.FallthroughDest) { - } - - ~AddSwitchNest() { - SC.FallthroughSource = OuterFallthroughSource; - SC.FallthroughDest = OuterFallthroughDest; - } - }; StmtChecker(DeclContext *DC) : Ctx(DC->getASTContext()), DC(DC) { } @@ -976,7 +892,8 @@ class StmtChecker : public StmtVisitor { Stmt *visitIfStmt(IfStmt *IS) { typeCheckConditionForStatement(IS, DC); - AddLabeledStmt ifNest(*this, IS); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, IS); Stmt *S = IS->getThenStmt(); typeCheckStmt(S); @@ -1000,7 +917,9 @@ class StmtChecker : public StmtVisitor { } Stmt *visitDoStmt(DoStmt *DS) { - AddLabeledStmt loopNest(*this, DS); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, DS); + BraceStmt *S = DS->getBody(); typeCheckStmt(S); DS->setBody(S); @@ -1010,7 +929,9 @@ class StmtChecker : public StmtVisitor { Stmt *visitWhileStmt(WhileStmt *WS) { typeCheckConditionForStatement(WS, DC); - AddLabeledStmt loopNest(*this, WS); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, WS); + Stmt *S = WS->getBody(); typeCheckStmt(S); WS->setBody(S); @@ -1018,12 +939,12 @@ class StmtChecker : public StmtVisitor { return WS; } Stmt *visitRepeatWhileStmt(RepeatWhileStmt *RWS) { - { - AddLabeledStmt loopNest(*this, RWS); - Stmt *S = RWS->getBody(); - typeCheckStmt(S); - RWS->setBody(S); - } + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, RWS); + + Stmt *S = RWS->getBody(); + typeCheckStmt(S); + RWS->setBody(S); Expr *E = RWS->getCond(); TypeChecker::typeCheckCondition(E, DC); @@ -1036,7 +957,9 @@ class StmtChecker : public StmtVisitor { return nullptr; // Type-check the body of the loop. - AddLabeledStmt loopNest(*this, S); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, S); + BraceStmt *Body = S->getBody(); typeCheckStmt(Body); S->setBody(Body); @@ -1048,7 +971,7 @@ class StmtChecker : public StmtVisitor { if (auto target = findBreakOrContinueStmtTarget( getASTContext(), DC->getParentSourceFile(), S->getLoc(), S->getTargetName(), S->getTargetLoc(), /*isContinue=*/false, - DC, ActiveLabeledStmts)) { + DC)) { S->setTarget(target); } @@ -1059,7 +982,7 @@ class StmtChecker : public StmtVisitor { if (auto target = findBreakOrContinueStmtTarget( getASTContext(), DC->getParentSourceFile(), S->getLoc(), S->getTargetName(), S->getTargetLoc(), /*isContinue=*/true, - DC, ActiveLabeledStmts)) { + DC)) { S->setTarget(target); } @@ -1067,7 +990,7 @@ class StmtChecker : public StmtVisitor { } Stmt *visitFallthroughStmt(FallthroughStmt *S) { - if (checkFallthroughStmt(DC, S, FallthroughSource, FallthroughDest)) + if (checkFallthroughStmt(DC, S)) return nullptr; return S; @@ -1213,13 +1136,6 @@ class StmtChecker : public StmtVisitor { for (auto i = casesBegin; i != casesEnd; ++i) { auto *caseBlock = *i; - if (parentKind == CaseParentKind::Switch) { - // Fallthrough transfers control to the next case block. In the - // final case block, it is invalid. Only switch supports fallthrough. - FallthroughSource = caseBlock; - FallthroughDest = std::next(i) == casesEnd ? nullptr : *std::next(i); - } - // Check restrictions on '@unknown'. if (caseBlock->hasUnknownAttr()) { assert(parentKind == CaseParentKind::Switch && @@ -1246,8 +1162,8 @@ class StmtChecker : public StmtVisitor { Type subjectType = switchStmt->getSubjectExpr()->getType(); // Type-check the case blocks. - AddSwitchNest switchNest(*this); - AddLabeledStmt labelNest(*this, switchStmt); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, switchStmt); // Pre-emptively visit all Decls (#if/#warning/#error) that still exist in // the list of raw cases. @@ -1278,7 +1194,8 @@ class StmtChecker : public StmtVisitor { // The labels are in scope for both the 'do' and all of the catch // clauses. This allows the user to break out of (or restart) the // entire construct. - AddLabeledStmt loopNest(*this, S); + auto sourceFile = DC->getParentSourceFile(); + checkLabeledStmtShadowing(getASTContext(), sourceFile, S); // Type-check the 'do' body. Type failures in here will generally // not cause type failures in the 'catch' clauses. From 70b68d6ba93ff6eb3ac0a969af2921507eb220cb Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Fri, 4 Sep 2020 16:05:37 -0400 Subject: [PATCH 584/663] [stdlib] Include Float16 among source types recognized for generic conversion --- stdlib/public/core/FloatingPoint.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stdlib/public/core/FloatingPoint.swift b/stdlib/public/core/FloatingPoint.swift index c0f60afd2446e..f759a0709da1e 100644 --- a/stdlib/public/core/FloatingPoint.swift +++ b/stdlib/public/core/FloatingPoint.swift @@ -1891,6 +1891,10 @@ extension BinaryFloatingPoint { @inlinable public init(_ value: Source) { switch value { +#if !os(macOS) && !(os(iOS) && targetEnvironment(macCatalyst)) + case let value_ as Float16: + self = Self(Float(value_)) +#endif case let value_ as Float: self = Self(value_) case let value_ as Double: From e4f6041dba818a82fcc918bc29cdd1a9ba8e63e8 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 4 Sep 2020 13:22:08 -0700 Subject: [PATCH 585/663] [ConstraintSystem] Record generic fix if destination of a pointer conversion is invalid If the right-hand side (destination) of value-to-pointer conversion is incorrect e.g. base type of member is a hole, let's record a generic "invalid conversion" failure. Resolves: rdar://problem/68254165 --- lib/Sema/CSSimplify.cpp | 7 +++++-- test/Constraints/valid_pointer_conversions.swift | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index a6563aa7fa550..86ae993fb893d 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3829,8 +3829,11 @@ bool ConstraintSystem::repairFailures( // If this is an implicit 'something-to-pointer' conversion // it's going to be diagnosed by specialized fix which deals // with generic argument mismatches. - if (matchKind == ConstraintKind::BindToPointerType) - break; + if (matchKind == ConstraintKind::BindToPointerType) { + auto *member = rhs->getAs(); + if (!(member && member->getBase()->hasHole())) + break; + } // If this is a ~= operator implicitly generated by pattern matching // let's not try to fix right-hand side of the operator because it's diff --git a/test/Constraints/valid_pointer_conversions.swift b/test/Constraints/valid_pointer_conversions.swift index 3a3bd9ea9cbc4..1cb1fb4ff1887 100644 --- a/test/Constraints/valid_pointer_conversions.swift +++ b/test/Constraints/valid_pointer_conversions.swift @@ -41,3 +41,9 @@ func SR12382(_ x: UnsafeMutablePointer??) {} var i = 0 SR12382(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePointer' to expected argument type 'UnsafeMutablePointer'}} // expected-note@-1 {{arguments to generic parameter 'Pointee' ('Int' and 'Double') are expected to be equal}} + +//problem/68254165 - Bad diagnostic when using String init(decodingCString:) with an incorrect pointer type +func rdar68254165(ptr: UnsafeMutablePointer) { + _ = String(decodingCString: ptr, as: .utf8) // expected-error {{generic parameter 'Encoding' could not be inferred}} + // expected-error@-1 {{type '_.Type' has no member 'utf8'}} +} From 6489e1aaacf85ff0fafc53b2b30d03519f5875e9 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 4 Sep 2020 12:49:17 -0700 Subject: [PATCH 586/663] [Concurrency] Fix nested await/try parsing and effects checking. Fix the parsing of await/try/try?/try! so that the two can be nested (e.g., `await try f()` or `try await f()`). Then, fix the effects checking logic to preserve all throws-related information under an `await`, and preserve all async/await-related information under `try`/`try?`/`try!`. Add a number of tests, and fix 'await' handling for string interpolations as well. --- lib/Parse/ParseExpr.cpp | 7 +++- lib/Sema/TypeCheckEffects.cpp | 32 +++++++++++++++ test/ClangImporter/objc_async.swift | 10 ++--- test/expr/unary/async_await.swift | 63 ++++++++++++++++++++++++++++- 4 files changed, 103 insertions(+), 9 deletions(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 7c753b4c2f226..accdc19250e49 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -394,7 +394,8 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, if (shouldParseExperimentalConcurrency() && Tok.isContextualKeyword("await")) { SourceLoc awaitLoc = consumeToken(); - ParserResult sub = parseExprUnary(message, isExprBasic); + ParserResult sub = + parseExprSequenceElement(diag::expected_expr_after_await, isExprBasic); if (!sub.hasCodeCompletion() && !sub.isNull()) { ElementContext.setCreateSyntax(SyntaxKind::AwaitExpr); sub = makeParserResult(new (Context) AwaitExpr(awaitLoc, sub.get())); @@ -428,7 +429,9 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, } } - ParserResult sub = parseExprUnary(message, isExprBasic); + ParserResult sub = hadTry + ? parseExprSequenceElement(message, isExprBasic) + : parseExprUnary(message, isExprBasic); if (hadTry && !sub.hasCodeCompletion() && !sub.isNull()) { ElementContext.setCreateSyntax(SyntaxKind::TryExpr); diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 4c595ca7f9eba..09b4eaf4a3297 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1329,6 +1329,29 @@ class CheckEffectsCoverage : public EffectsHandlingWalker void mergeFrom(ContextFlag flag, ContextFlags other) { Bits |= (other.Bits & flag); } + + void mergeFrom(ContextFlags flags, ContextFlags other) { + Bits |= (other.Bits & flags.Bits); + } + + // All of the flags that can be set by throw checking. + static ContextFlags throwFlags() { + ContextFlags result; + result.set(IsTryCovered); + result.set(IsInTry); + result.set(HasAnyThrowSite); + result.set(HasTryThrowSite); + return result; + } + + // All of the flags that can be set by async/await checking. + static ContextFlags asyncAwaitFlags() { + ContextFlags result; + result.set(IsAsyncCovered); + result.set(HasAnyAsyncSite); + result.set(HasAnyAwait); + return result; + } }; ContextFlags Flags; @@ -1408,6 +1431,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker // body for the purposes of deciding whether a try contained // a throwing call. OldFlags.mergeFrom(ContextFlags::HasTryThrowSite, Self.Flags); + + // "await" doesn't work this way; the "await" needs to be part of + // the autoclosure expression itself, and the autoclosure must be + // 'async'. } void preserveCoverageFromNonExhaustiveCatch() { @@ -1417,16 +1444,21 @@ class CheckEffectsCoverage : public EffectsHandlingWalker void preserveCoverageFromAwaitOperand() { OldFlags.mergeFrom(ContextFlags::HasAnyAwait, Self.Flags); + OldFlags.mergeFrom(ContextFlags::throwFlags(), Self.Flags); + OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind); } void preserveCoverageFromTryOperand() { OldFlags.mergeFrom(ContextFlags::HasAnyThrowSite, Self.Flags); + OldFlags.mergeFrom(ContextFlags::asyncAwaitFlags(), Self.Flags); OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind); } void preserveCoverageFromInterpolatedString() { OldFlags.mergeFrom(ContextFlags::HasAnyThrowSite, Self.Flags); OldFlags.mergeFrom(ContextFlags::HasTryThrowSite, Self.Flags); + OldFlags.mergeFrom(ContextFlags::HasAnyAsyncSite, Self.Flags); + OldFlags.mergeFrom(ContextFlags::HasAnyAwait, Self.Flags); OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind); } diff --git a/test/ClangImporter/objc_async.swift b/test/ClangImporter/objc_async.swift index 15b149a89c5dd..1a30f41c97a44 100644 --- a/test/ClangImporter/objc_async.swift +++ b/test/ClangImporter/objc_async.swift @@ -1,16 +1,14 @@ -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules -enable-experimental-concurrency %s -verify +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules -enable-experimental-concurrency %s -verify // REQUIRES: objc_interop import Foundation import ObjCConcurrency -func testSlowServer(slowServer: SlowServer) async { +func testSlowServer(slowServer: SlowServer) async throws { let _: Int = await slowServer.doSomethingSlow("mail") let _: Bool = await slowServer.checkAvailability() - let _: String = await slowServer.findAnswer() ?? "nope" - let _: String = await slowServer.findAnswerFailingly() ?? "nope" - // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} - // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} + let _: String = try await slowServer.findAnswer() ?? "nope" + let _: String = await try slowServer.findAnswerFailingly() ?? "nope" let _: Void = await slowServer.doSomethingFun("jump") let _: (Int) -> Void = slowServer.completionHandler } diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift index 3601108f8e90c..3dc31a35ab1c9 100644 --- a/test/expr/unary/async_await.swift +++ b/test/expr/unary/async_await.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency +// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency -verify-syntax-tree func test1(asyncfp : () async -> Int, fp : () -> Int) async { _ = await asyncfp() @@ -72,3 +72,64 @@ func testClosure() { let _: () -> Int = closure2 // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} } + +// Nesting async and await together +func throwingAndAsync() async throws -> Int { return 0 } + +enum HomeworkError : Error { + case dogAteIt +} + +func testThrowingAndAsync() async throws { + _ = await try throwingAndAsync() + _ = try await throwingAndAsync() + _ = await (try throwingAndAsync()) + _ = try (await throwingAndAsync()) + + // Errors + _ = await throwingAndAsync() // expected-error{{call can throw but is not marked with 'try'}} + // expected-note@-1{{did you mean to use 'try'?}} + // expected-note@-2{{did you mean to handle error as optional value?}} + // expected-note@-3{{did you mean to disable error propagation?}} + _ = try throwingAndAsync() // expected-error{{call is 'async' but is not marked with 'await'}} +} + +func testExhaustiveDoCatch() async { + do { + _ = await try throwingAndAsync() + } catch { + } + + do { + _ = await try throwingAndAsync() + // expected-error@-1{{errors thrown from here are not handled because the enclosing catch is not exhaustive}} + } catch let e as HomeworkError { + } + + // Ensure that we infer 'async' through an exhaustive do-catch. + let fn = { + do { + _ = await try throwingAndAsync() + } catch { + } + } + + let _: Int = fn // expected-error{{cannot convert value of type '() async -> ()'}} + + // Ensure that we infer 'async' through a non-exhaustive do-catch. + let fn2 = { + do { + _ = await try throwingAndAsync() + } catch let e as HomeworkError { + } + } + + let _: Int = fn2 // expected-error{{cannot convert value of type '() async throws -> ()'}} +} + +// String interpolation +func testStringInterpolation() async throws { + _ = "Eventually produces \(getInt())" // expected-error{{call is 'async' but is not marked with 'await'}} + _ = "Eventually produces \(await getInt())" + _ = await "Eventually produces \(getInt())" +} From b6046352deda78c4d73a8ba47b2c017c070f271b Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Fri, 4 Sep 2020 17:51:39 -0400 Subject: [PATCH 587/663] =?UTF-8?q?=F0=9F=A4=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stdlib/public/core/FloatingPoint.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stdlib/public/core/FloatingPoint.swift b/stdlib/public/core/FloatingPoint.swift index f759a0709da1e..9f931663e9923 100644 --- a/stdlib/public/core/FloatingPoint.swift +++ b/stdlib/public/core/FloatingPoint.swift @@ -1890,11 +1890,15 @@ extension BinaryFloatingPoint { /// - Parameter value: A floating-point value to be converted. @inlinable public init(_ value: Source) { - switch value { #if !os(macOS) && !(os(iOS) && targetEnvironment(macCatalyst)) - case let value_ as Float16: - self = Self(Float(value_)) + if #available(iOS 14.0, watchOS 7.0, tvOS 14.0, *) { + if case let value_ as Float16 = value { + self = Self(Float(value_)) + return + } + } #endif + switch value { case let value_ as Float: self = Self(value_) case let value_ as Double: From 193cf0de87947d99a0625b9032552b0303adaba2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 4 Sep 2020 16:20:34 -0400 Subject: [PATCH 588/663] Code review feedback from @davidungar --- include/swift/AST/SourceFile.h | 4 +--- lib/AST/Module.cpp | 6 ++++++ lib/Parse/ParseDecl.cpp | 25 +++++++++++++------------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index 86af09971f60a..5fc32b5983f94 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -236,9 +236,7 @@ class SourceFile final : public FileUnit { } /// Add a hoisted declaration. See Decl::isHoisted(). - void addHoistedDecl(Decl *d) { - Hoisted.push_back(d); - } + void addHoistedDecl(Decl *d); /// Retrieves an immutable view of the list of top-level decls in this file. ArrayRef getTopLevelDecls() const; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 35fa382c742e4..69075ff7a08d9 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2337,6 +2337,12 @@ bool SourceFile::hasDelayedBodyParsing() const { return true; } +/// Add a hoisted declaration. See Decl::isHoisted(). +void SourceFile::addHoistedDecl(Decl *d) { + assert(d->isHoisted()); + Hoisted.push_back(d); +} + ArrayRef SourceFile::getTopLevelDecls() const { auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 32c7d78b54edb..94f0d5825ff33 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -104,30 +104,24 @@ namespace { template ParserResult fixupParserResult(T *D) { - if (movedToTopLevel()) { - D->setHoisted(); - SF->addHoistedDecl(D); - getDebuggerClient()->didGlobalize(D); - } + if (movedToTopLevel()) + hoistDecl(D); return ParserResult(D); } template ParserResult fixupParserResult(ParserStatus Status, T *D) { - if (movedToTopLevel()) { - D->setHoisted(); - SF->addHoistedDecl(D); - getDebuggerClient()->didGlobalize(D); - } + if (movedToTopLevel()) + hoistDecl(D); return makeParserResult(Status, D); } // The destructor doesn't need to do anything, the CC's destructor will // pop the context if we set it. ~DebuggerContextChange () {} - protected: - + + private: DebuggerClient *getDebuggerClient() { ModuleDecl *M = P.CurDeclContext->getParentModule(); return M->getDebugClient(); @@ -152,6 +146,13 @@ namespace { SF = P.CurDeclContext->getParentSourceFile(); CC.emplace(P, SF); } + + template + void hoistDecl(T *D) { + D->setHoisted(); + SF->addHoistedDecl(D); + getDebuggerClient()->didGlobalize(D); + } }; } // end anonymous namespace From 6fbbc498e5e019f425ef8cb3af66e9e6f6e0867f Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Fri, 4 Sep 2020 17:27:23 -0700 Subject: [PATCH 589/663] Delete build-windows-rebranch.bat --- utils/build-windows-rebranch.bat | 349 ------------------------------- 1 file changed, 349 deletions(-) delete mode 100644 utils/build-windows-rebranch.bat diff --git a/utils/build-windows-rebranch.bat b/utils/build-windows-rebranch.bat deleted file mode 100644 index feb14fe07d361..0000000000000 --- a/utils/build-windows-rebranch.bat +++ /dev/null @@ -1,349 +0,0 @@ -:: build-windows.bat -:: -:: This source file is part of the Swift.org open source project -:: -:: Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors -:: Licensed under Apache License v2.0 with Runtime Library Exception -:: -:: See https://swift.org/LICENSE.txt for license information -:: See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors - -:: REQUIRED ENVIRONMENT VARIABLES -:: This script requires to be executed inside one Visual Studio command line, -:: in order for many of the tools and environment variables to be available. -:: Additionally, it needs the following variables: -:: - CMAKE_BUILD_TYPE: Kind of build: Release, RelWithDebInfo, Debug. -:: - PYTHON_HOME: The Python installation directory. - -:: REQUIRED PERMISSIONS -:: Practically, it is easier to be in the Adminstrators group to run the -:: script, but it should be possible to execute as a normal user. -:: The user will need permission to write files into the Windows SDK and the -:: VisualC++ folder. - -:: @echo off - -setlocal enableextensions enabledelayedexpansion - -set icu_version_major=64 -set icu_version_minor=2 -set icu_version=%icu_version_major%_%icu_version_minor% -set icu_version_dashed=%icu_version_major%-%icu_version_minor% - -set "exitOnError=|| (exit /b)" -set current_directory=%~dp0 -set current_directory=%current_directory:~0,-1% -set source_root=%current_directory%\..\.. - -:: Resetting source_root with %CD% removes the ..\.. from the paths, and makes -:: the output easier to read. -cd %source_root% -set source_root=%CD% - -set full_build_root=%source_root%\build -mkdir %full_build_root% - -:: Use the shortest path we can for the build directory, to avoid Windows -:: path problems as much as we can. -subst T: /d -subst T: %full_build_root% %exitOnError% -set build_root=T: -set install_directory=%build_root%\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr - -md %build_root%\tmp -set TMPDIR=%build_root%\tmp - -md %build_root%\tmp\org.llvm.clang -set CUSTOM_CLANG_MODULE_CACHE=%build_root%\tmp\org.llvm.clang.9999 - -md %build_root%\tmp\org.swift.package-manager -set SWIFTPM_MODULECACHE_OVERRIDE=%build_root%\tmp\org.swift.package-manager - -call :clone_repositories %exitOnError% -call :download_icu %exitOnError% -:: TODO: Disabled until we need LLBuild/SwiftPM in this build script. -:: call :download_sqlite3 - -call :build_llvm %exitOnError% -path %PATH%;%install_directory%\bin - -call :build_cmark %exitOnError% - -call :prepare_platform_modules %exitOnError% -call :build_swift %exitOnError% - -call :build_lldb %exitOnError% - -call :build_libdispatch %exitOnError% - -path %source_root%\icu-%icu_version%\bin64;%install_directory%\bin;%build_root%\swift\bin;%build_root%\swift\libdispatch-prefix\bin;%PATH%;C:\Program Files\Git\usr\bin -call :test_swift %exitOnError% -call :test_libdispatch %exitOnError% - -goto :end -endlocal - -:clone_repositories -:: Clones the repositories used by the Windows build. -:: It supposes that the swift repository is already cloned by CI. -:: It supposes the %CD% is the source root. -setlocal enableextensions enabledelayedexpansion - -git -C "%source_root%\swift" config --local core.autocrlf input -git -C "%source_root%\swift" config --local core.symlink true -git -C "%source_root%\swift" checkout-index --force --all - -git clone --depth 1 --single-branch https://github.com/apple/swift-cmark cmark %exitOnError% -git clone --depth 1 --single-branch --branch swift/master-rebranch https://github.com/apple/llvm-project llvm-project %exitOnError% -mklink /D "%source_root%\clang" "%source_root%\llvm-project\clang" -mklink /D "%source_root%\llvm" "%source_root%\llvm-project\llvm" -mklink /D "%source_root%\lld" "%source_root%\llvm-project\lld" -mklink /D "%source_root%\lldb" "%source_root%\llvm-project\lldb" -mklink /D "%source_root%\compiler-rt" "%source_root%\llvm-project\compiler-rt" -mklink /D "%source_root%\libcxx" "%source_root%\llvm-project\libcxx" -mklink /D "%source_root%\clang-tools-extra" "%source_root%\llvm-project\clang-tools-extra" -git clone --depth 1 --single-branch https://github.com/apple/swift-corelibs-libdispatch %exitOnError% - -goto :eof -endlocal - - -:download_icu -:: Downloads ICU, which will be used as a dependency for the Swift Standard -:: Library and Foundation. -setlocal enableextensions enabledelayedexpansion - -set file_name=icu4c-%icu_version%-Win64-MSVC2017.zip -curl -L -O "https://github.com/unicode-org/icu/releases/download/release-%icu_version_dashed%/%file_name%" %exitOnError% -:: unzip warns about the paths in the zip using slashes, which raises the -:: errorLevel to 1. We cannot use exitOnError, and have to ignore errors. -"C:\Program Files\Git\usr\bin\unzip.exe" -o %file_name% -d "%source_root%\icu-%icu_version%" -exit /b 0 - -goto :eof -endlocal - - -:download_sqlite3 -:: Downloads SQLite3, which will be used as a dependency for llbuild and -:: Swift Package Manager. -setlocal enableextensions enabledelayedexpansion - -set file_name=sqlite-amalgamation-3270200.zip -curl -L -O "https://www.sqlite.org/2019/%file_name%" %exitOnError% -"C:\Program Files\Git\usr\bin\unzip.exe" -o %file_name% %exitOnError% - -goto :eof -endlocal - - -:prepare_platform_modules -:: Create files into the right places of the Windows SDK to the files in the -:: swift repository, in order to consider the headers of the Windows SDK a -:: module to compile Swift code against them. -setlocal enableextensions enabledelayedexpansion - -copy /y "%source_root%\swift\stdlib\public\Platform\ucrt.modulemap" "%UniversalCRTSdkDir%\Include\%UCRTVersion%\ucrt\module.modulemap" %exitOnError% -copy /y "%source_root%\swift\stdlib\public\Platform\winsdk.modulemap" "%UniversalCRTSdkDir%\Include\%UCRTVersion%\um\module.modulemap" %exitOnError% -copy /y "%source_root%\swift\stdlib\public\Platform\visualc.modulemap" "%VCToolsInstallDir%\include\module.modulemap" %exitOnError% -copy /y "%source_root%\swift\stdlib\public\Platform\visualc.apinotes" "%VCToolsInstallDir%\include\visualc.apinotes" %exitOnError% - -goto :eof -endlocal - - -:build_llvm -:: Configures, builds, and installs LLVM -setlocal enableextensions enabledelayedexpansion - -cmake^ - -B "%build_root%\llvm"^ - -G Ninja^ - -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=cl^ - -DCMAKE_CXX_COMPILER=cl^ - -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ - -DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-windows-msvc^ - -DLLVM_ENABLE_PDB:BOOL=YES^ - -DLLVM_ENABLE_ASSERTIONS:BOOL=YES^ - -DLLVM_ENABLE_PROJECTS:STRING=lld;clang^ - -DLLVM_TARGETS_TO_BUILD:STRING="AArch64;ARM;X86"^ - -DLLVM_INCLUDE_BENCHMARKS:BOOL=NO^ - -DLLVM_INCLUDE_DOCS:BOOL=NO^ - -DLLVM_INCLUDE_EXAMPLES:BOOL=NO^ - -DLLVM_INCLUDE_GO_TESTS:BOOL=NO^ - -DLLVM_TOOL_GOLD_BUILD:BOOL=NO^ - -DLLVM_ENABLE_OCAMLDOC:BOOL=NO^ - -DLLVM_ENABLE_LIBXML2:BOOL=NO^ - -DLLVM_ENABLE_ZLIB:BOOL=NO^ - -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ - -DENABLE_X86_RELAX_RELOCATIONS:BOOL=YES^ - -DLLVM_INSTALL_BINUTILS_SYMLINKS:BOOL=YES^ - -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ - -DLLVM_TOOLCHAIN_TOOLS:STRING="addr2line;ar;c++filt;dsymutil;dwp;llvm-ar;llvm-cov;llvm-cvtres;llvm-cxxfilt;llvm-dlltool;llvm-dwp;llvm-ranlib;llvm-lib;llvm-mt;llvm-nm;llvm-objdump;llvm-pdbutil;llvm-profdata;llvm-rc;llvm-readelf;llvm-readobj;llvm-size;llvm-strip;llvm-symbolizer;llvm-undname;nm;objcopy;objdump;ranlib;readelf;size;strings"^ - -DCLANG_TOOLS="clang;clang-format;clang-headers;clang-tidy"^ - -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ - -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -S "%source_root%\llvm" %exitOnError% - -cmake --build "%build_root%\llvm" %exitOnError% -cmake --build "%build_root%\llvm" --target install %exitOnError% - -goto :eof -endlocal - - -:build_cmark -:: Configures and builds CMark -setlocal enableextensions enabledelayedexpansion - -cmake^ - -B "%build_root%\cmark"^ - -G Ninja^ - -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=cl^ - -DCMAKE_CXX_COMPILER=cl^ - -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ - -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -S "%source_root%\cmark" %exitOnError% - -cmake --build "%build_root%\cmark" %exitOnError% - -goto :eof -endlocal - - -:build_swift -:: Configures, builds, and installs Swift and the Swift Standard Library -setlocal enableextensions enabledelayedexpansion - -:: SWIFT_PARALLEL_LINK_JOBS=8 allows the build machine to use as many CPU as -:: possible, while not exhausting the RAM. -cmake^ - -B "%build_root%\swift"^ - -G Ninja^ - -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=cl^ - -DCMAKE_CXX_COMPILER=cl^ - -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ - -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ - -DSWIFT_PATH_TO_CMARK_BUILD:PATH=%build_root%\cmark^ - -DSWIFT_PATH_TO_CMARK_SOURCE:PATH=%source_root%\cmark^ - -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH=%source_root%\swift-corelibs-libdispatch^ - -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ - -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ - -DSWIFT_INCLUDE_DOCS:BOOL=NO^ - -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE:PATH=%source_root%\icu-%icu_version%\include\unicode^ - -DSWIFT_WINDOWS_x86_64_ICU_UC:PATH=%source_root%\icu-%icu_version%\lib64\icuuc.lib^ - -DSWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE:PATH=%source_root%\icu-%icu_version%\include^ - -DSWIFT_WINDOWS_x86_64_ICU_I18N:PATH=%source_root%\icu-%icu_version%\lib64\icuin.lib^ - -DSWIFT_BUILD_DYNAMIC_STDLIB:BOOL=YES^ - -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY:BOOL=YES^ - -DSWIFT_BUILD_STATIC_STDLIB:BOOL=NO^ - -DSWIFT_BUILD_STATIC_SDK_OVERLAY:BOOL=NO^ - -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ - -DSWIFT_BUILD_SOURCEKIT:BOOL=YES^ - -DSWIFT_ENABLE_SOURCEKIT_TESTS:BOOL=YES^ - -DSWIFT_INSTALL_COMPONENTS="autolink-driver;compiler;clang-resource-dir-symlink;stdlib;sdk-overlay;editor-integration;tools;sourcekit-inproc;swift-remote-mirror;swift-remote-mirror-headers"^ - -DSWIFT_PARALLEL_LINK_JOBS=8^ - -DPYTHON_EXECUTABLE:PATH=%PYTHON_HOME%\python.exe^ - -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ - -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -S "%source_root%\swift" %exitOnError% - -cmake --build "%build_root%\swift" %exitOnError% -cmake --build "%build_root%\swift" --target install %exitOnError% - -goto :eof -endlocal - - -:test_swift -:: Tests the Swift compiler and the Swift Standard Library -setlocal enableextensions enabledelayedexpansion - -cmake --build "%build_root%\swift" --target check-swift %exitOnError% - -goto :eof -endlocal - - -:build_lldb -:: Configures, builds, and installs LLDB -setlocal enableextensions enabledelayedexpansion - -cmake^ - -B "%build_root%\lldb"^ - -G Ninja^ - -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=cl^ - -DCMAKE_CXX_COMPILER=cl^ - -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ - -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ - -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ - -DSwift_DIR:PATH=%build_root%\swift\lib\cmake\swift^ - -DLLVM_ENABLE_ASSERTIONS:BOOL=YES^ - -DLLDB_USE_STATIC_BINDINGS:BOOL=YES^ - -DPYTHON_HOME:PATH=%PYTHON_HOME%^ - -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ - -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -DLLDB_DISABLE_PYTHON=YES^ - -DLLDB_INCLUDE_TESTS:BOOL=NO^ - -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ - -S "%source_root%\lldb" %exitOnError% - -cmake --build "%build_root%\lldb" %exitOnError% -cmake --build "%build_root%\lldb" --target install %exitOnError% - -goto :eof -endlocal - - -:build_libdispatch -:: Configures, builds, and installs Dispatch -setlocal enableextensions enabledelayedexpansion - -cmake^ - -B "%build_root%\swift-corelibs-libdispatch"^ - -G Ninja^ - -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=clang-cl^ - -DCMAKE_CXX_COMPILER=clang-cl^ - -DCMAKE_Swift_COMPILER=swiftc^ - -DSwift_DIR:PATH=%build_root%\swift\lib\cmake\swift^ - -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ - -DCMAKE_C_COMPILER_TARGET=x86_64-unknown-windows-msvc^ - -DCMAKE_CXX_COMPILER_TARGET=x86_64-unknown-windows-msvc^ - -DENABLE_SWIFT:BOOL=YES^ - -DENABLE_TESTING:BOOL=YES^ - -DCMAKE_C_FLAGS:STRING="${CMAKE_C_FLAGS} --target=x86_64-unknown-windows-msvc /GS- /Oy /Gw /Gy"^ - -DCMAKE_CXX_FLAGS:STRING="${CMAKE_CXX_FLAGS} --target=x86_64-unknown-windows-msvc /GS- /Oy /Gw /Gy"^ - -DCMAKE_EXE_LINKER_FLAGS:STRING="/INCREMENTAL:NO"^ - -DCMAKE_SHARED_LINKER_FLAGS:STRING="/INCREMENTAL:NO"^ - -DCMAKE_Swift_COMPILER_TARGET:STRING=x86_64-unknown-windows-msvc^ - -DCMAKE_Swift_FLAGS:STRING="-resource-dir \"%install_directory%\lib\swift\""^ - -DCMAKE_Swift_LINK_FLAGS:STRING="-resource-dir \"%install_directory%\lib\swift\""^ - -S "%source_root%\swift-corelibs-libdispatch" %exitOnError% - -cmake --build "%build_root%\swift-corelibs-libdispatch" %exitOnError% -cmake --build "%build_root%\swift-corelibs-libdispatch" --target install %exitOnError% - -goto :eof -endlocal - - -:test_libdispatch -:: Tests libdispatch C interface -setlocal enableextensions enabledelayedexpansion - -cmake --build "%build_root%\swift-corelibs-libdispatch" --target ExperimentalTest %exitOnError% - -goto :eof -endlocal - - -:end From 4fa57aef130d5a3d5688ebc999de32e504044d22 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 4 Sep 2020 14:03:48 -0700 Subject: [PATCH 590/663] [serialization] Refactor from large SILInstruction loop, writeNoOperandLayout handler. NFC. --- lib/Serialization/SerializeSIL.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index fe1c2dd967a96..7c81a0c7bf579 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -248,6 +248,12 @@ namespace { void writeSILBlock(const SILModule *SILMod); void writeIndexTables(); + void writeNoOperandLayout(const SILInstruction *I) { + unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code]; + SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, + (unsigned)I->getKind()); + } + void writeConversionLikeInstruction(const SingleValueInstruction *I, unsigned attrs); void writeOneTypeLayout(SILInstructionKind valueKind, @@ -763,9 +769,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { case SILInstructionKind::UnwindInst: case SILInstructionKind::UnreachableInst: { - unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code]; - SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, - (unsigned)SI.getKind()); + writeNoOperandLayout(&SI); break; } case SILInstructionKind::AllocExistentialBoxInst: From c54fb3391108b5d3e141c48d01b83c8acf12a739 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 4 Sep 2020 20:08:40 -0700 Subject: [PATCH 591/663] [opt-remark] Infer the source loc retain, release even if they have non-inlined locs. The reason why is that due to ARCCodeMotion, they could have moved enough that the SourceLoc on them is incorrect. That is why you can see in the tests that I had to update, I am moving the retain to the return statement from the body of the function since the retain was now right before the return. I also went in and cleaned up the logic here a little bit. What we do now is that we have a notion of instructions that we /always/ infer SourceLocs for (rr) and ones that if we have a valid non-inlined location we use (e.x.: allocations). This mucked a little bit with my ability to run SIL tests since the SIL tests were relying on this not happening to rr so that we would emit remarks on the rr instructions themselves. I added an option that disables the always infer behavior for this test. That being said at this point to me it seems like the SourceLoc inference stuff is really tied to OptRemarkGenerator and I am going to see if I can move it to there. But that is for a future commit on another day. --- include/swift/SIL/OptimizationRemark.h | 24 ++++++-- lib/SIL/Utils/OptimizationRemark.cpp | 61 ++++++++----------- .../Transforms/OptRemarkGenerator.cpp | 45 +++++++------- test/SILOptimizer/opt-remark-generator.sil | 2 +- test/SILOptimizer/opt-remark-generator.swift | 6 +- 5 files changed, 71 insertions(+), 67 deletions(-) diff --git a/include/swift/SIL/OptimizationRemark.h b/include/swift/SIL/OptimizationRemark.h index 632b6b7e45d19..3e3c05cb6463f 100644 --- a/include/swift/SIL/OptimizationRemark.h +++ b/include/swift/SIL/OptimizationRemark.h @@ -137,14 +137,26 @@ struct IndentDebug { unsigned width; }; -enum class SourceLocInferenceBehavior { - None, - ForwardScanOnly, - BackwardScanOnly, - ForwardThenBackward, - BackwardThenForward, +enum class SourceLocInferenceBehavior : unsigned { + None = 0, + ForwardScan = 0x1, + BackwardScan = 0x2, + ForwardScan2nd = 0x4, + AlwaysInfer = 0x8, + + ForwardThenBackwards = ForwardScan | BackwardScan, + BackwardsThenForwards = BackwardScan | ForwardScan2nd, + ForwardScanAlwaysInfer = ForwardScan | AlwaysInfer, + BackwardScanAlwaysInfer = BackwardScan | AlwaysInfer, }; +inline SourceLocInferenceBehavior operator&(SourceLocInferenceBehavior lhs, + SourceLocInferenceBehavior rhs) { + auto lhsVal = std::underlying_type::type(lhs); + auto rhsVal = std::underlying_type::type(rhs); + return SourceLocInferenceBehavior(lhsVal & rhsVal); +} + /// Infer the proper SourceLoc to use for the given SILInstruction. /// /// This means that if we have a valid location for the instruction, we just diff --git a/lib/SIL/Utils/OptimizationRemark.cpp b/lib/SIL/Utils/OptimizationRemark.cpp index 6a778f0266c16..978527366bb05 100644 --- a/lib/SIL/Utils/OptimizationRemark.cpp +++ b/lib/SIL/Utils/OptimizationRemark.cpp @@ -182,59 +182,48 @@ static SourceLoc inferOptRemarkSearchBackwards(SILInstruction &i) { return SourceLoc(); } +static llvm::cl::opt IgnoreAlwaysInferForTesting( + "sil-opt-remark-ignore-always-infer", llvm::cl::Hidden, + llvm::cl::init(false), + llvm::cl::desc( + "Disables always infer source loc behavior for testing purposes")); + +// Attempt to infer a SourceLoc for \p i using heuristics specified by \p +// inferBehavior. +// +// NOTE: We distinguish in between situations where we always must infer +// (retain, release) and other situations where we are ok with original source +// locs if we are not inlined (alloc_ref, alloc_stack). SourceLoc swift::OptRemark::inferOptRemarkSourceLoc( SILInstruction &i, SourceLocInferenceBehavior inferBehavior) { - // Do a quick check if we already have a valid loc and it isnt an inline - // loc. In such a case, just return. Otherwise, we try to infer using one of - // our heuristics below. + // If we are only supposed to infer in inline contexts, see if we have a valid + // loc and if that loc is an inlined call site. auto loc = i.getLoc(); - if (loc.getSourceLoc().isValid()) { - // Before we do anything, if we do not have an inlined call site, just - // return our loc. - if (!i.getDebugScope() || !i.getDebugScope()->InlinedCallSite) - return loc.getSourceLoc(); - } + if (loc.getSourceLoc().isValid() && + !(bool(inferBehavior & SourceLocInferenceBehavior::AlwaysInfer) && + !IgnoreAlwaysInferForTesting) && + !(i.getDebugScope() && i.getDebugScope()->InlinedCallSite)) + return loc.getSourceLoc(); - // Otherwise, try to handle the individual behavior cases, returning loc at - // the end of each case (its invalid, so it will get ignored). If loc is not - // returned, we hit an assert at the end to make it easy to identify a case - // was missed. - switch (inferBehavior) { - case SourceLocInferenceBehavior::None: - return SourceLoc(); - case SourceLocInferenceBehavior::ForwardScanOnly: { + if (bool(inferBehavior & SourceLocInferenceBehavior::ForwardScan)) { SourceLoc newLoc = inferOptRemarkSearchForwards(i); if (newLoc.isValid()) return newLoc; - return SourceLoc(); } - case SourceLocInferenceBehavior::BackwardScanOnly: { + + if (bool(inferBehavior & SourceLocInferenceBehavior::BackwardScan)) { SourceLoc newLoc = inferOptRemarkSearchBackwards(i); if (newLoc.isValid()) return newLoc; - return SourceLoc(); } - case SourceLocInferenceBehavior::ForwardThenBackward: { + + if (bool(inferBehavior & SourceLocInferenceBehavior::ForwardScan2nd)) { SourceLoc newLoc = inferOptRemarkSearchForwards(i); if (newLoc.isValid()) return newLoc; - newLoc = inferOptRemarkSearchBackwards(i); - if (newLoc.isValid()) - return newLoc; - return SourceLoc(); - } - case SourceLocInferenceBehavior::BackwardThenForward: { - SourceLoc newLoc = inferOptRemarkSearchBackwards(i); - if (newLoc.isValid()) - return newLoc; - newLoc = inferOptRemarkSearchForwards(i); - if (newLoc.isValid()) - return newLoc; - return SourceLoc(); - } } - llvm_unreachable("Covered switch isn't covered?!"); + return SourceLoc(); } template diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index 3b6cb4f116bb9..b1e98ba58ef38 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -425,10 +425,11 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongRetainInst( (void)foundArgs; // Retains begin a lifetime scope so we infer scan forward. - auto remark = RemarkMissed("memory", *sri, - SourceLocInferenceBehavior::ForwardScanOnly) - << "retain of type '" - << NV("ValueType", sri->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *sri, + SourceLocInferenceBehavior::ForwardScanAlwaysInfer) + << "retain of type '" << NV("ValueType", sri->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -446,10 +447,11 @@ void OptRemarkGeneratorInstructionVisitor::visitStrongReleaseInst( sri->getOperand(), inferredArgs); (void)foundArgs; - auto remark = RemarkMissed("memory", *sri, - SourceLocInferenceBehavior::BackwardScanOnly) - << "release of type '" - << NV("ValueType", sri->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *sri, + SourceLocInferenceBehavior::BackwardScanAlwaysInfer) + << "release of type '" << NV("ValueType", sri->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -466,10 +468,11 @@ void OptRemarkGeneratorInstructionVisitor::visitRetainValueInst( rvi->getOperand(), inferredArgs); (void)foundArgs; // Retains begin a lifetime scope, so we infer scan forwards. - auto remark = RemarkMissed("memory", *rvi, - SourceLocInferenceBehavior::ForwardScanOnly) - << "retain of type '" - << NV("ValueType", rvi->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *rvi, + SourceLocInferenceBehavior::ForwardScanAlwaysInfer) + << "retain of type '" << NV("ValueType", rvi->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -487,10 +490,11 @@ void OptRemarkGeneratorInstructionVisitor::visitReleaseValueInst( (void)foundArgs; // Releases end a lifetime scope so we infer scan backward. - auto remark = RemarkMissed("memory", *rvi, - SourceLocInferenceBehavior::BackwardScanOnly) - << "release of type '" - << NV("ValueType", rvi->getOperand()->getType()) << "'"; + auto remark = + RemarkMissed("memory", *rvi, + SourceLocInferenceBehavior::BackwardScanAlwaysInfer) + << "release of type '" << NV("ValueType", rvi->getOperand()->getType()) + << "'"; for (auto arg : inferredArgs) { remark << arg; } @@ -508,8 +512,7 @@ void OptRemarkGeneratorInstructionVisitor::visitAllocRefInst( valueToDeclInferrer.infer(ArgumentKeyKind::Note, ari, inferredArgs); (void)foundArgs; auto resultRemark = - RemarkPassed("memory", *ari, - SourceLocInferenceBehavior::ForwardScanOnly) + RemarkPassed("memory", *ari, SourceLocInferenceBehavior::ForwardScan) << "stack allocated ref of type '" << NV("ValueType", ari->getType()) << "'"; for (auto &arg : inferredArgs) @@ -526,8 +529,7 @@ void OptRemarkGeneratorInstructionVisitor::visitAllocRefInst( (void)foundArgs; auto resultRemark = - RemarkMissed("memory", *ari, - SourceLocInferenceBehavior::ForwardScanOnly) + RemarkMissed("memory", *ari, SourceLocInferenceBehavior::ForwardScan) << "heap allocated ref of type '" << NV("ValueType", ari->getType()) << "'"; for (auto &arg : inferredArgs) @@ -546,8 +548,7 @@ void OptRemarkGeneratorInstructionVisitor::visitAllocBoxInst( (void)foundArgs; auto resultRemark = - RemarkMissed("memory", *abi, - SourceLocInferenceBehavior::ForwardScanOnly) + RemarkMissed("memory", *abi, SourceLocInferenceBehavior::ForwardScan) << "heap allocated box of type '" << NV("ValueType", abi->getType()) << "'"; for (auto &arg : inferredArgs) diff --git a/test/SILOptimizer/opt-remark-generator.sil b/test/SILOptimizer/opt-remark-generator.sil index f7bf9b681ba8e..4e10c7fd151ac 100644 --- a/test/SILOptimizer/opt-remark-generator.sil +++ b/test/SILOptimizer/opt-remark-generator.sil @@ -1,4 +1,4 @@ -// RUN: %target-sil-opt -optremarkgen-declless-debugvalue-use-sildebugvar-info -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null +// RUN: %target-sil-opt -sil-opt-remark-ignore-always-infer -optremarkgen-declless-debugvalue-use-sildebugvar-info -sil-opt-remark-generator -sil-remarks-missed=sil-opt-remark-gen -verify %s -o /dev/null sil_stage canonical diff --git a/test/SILOptimizer/opt-remark-generator.swift b/test/SILOptimizer/opt-remark-generator.swift index 8c780ea9f571b..6aedcd8ca8dc8 100644 --- a/test/SILOptimizer/opt-remark-generator.swift +++ b/test/SILOptimizer/opt-remark-generator.swift @@ -90,8 +90,10 @@ func printKlassPairLHS(x : KlassPair) { // expected-remark @-3:16 {{release of type}} } +// We put the retain on the return here since it is part of the result +// convention. func returnKlassPairLHS(x: KlassPair) -> Klass { - return x.lhs // expected-remark @:14 {{retain of type 'Klass'}} + return x.lhs // expected-remark @:5 {{retain of type 'Klass'}} // expected-note @-2:25 {{of 'x.lhs'}} } @@ -123,7 +125,7 @@ func printKlassTupleLHS(x : (Klass, Klass)) { } func returnKlassTupleLHS(x: (Klass, Klass)) -> Klass { - return x.0 // expected-remark @:12 {{retain of type 'Klass'}} + return x.0 // expected-remark @:5 {{retain of type 'Klass'}} // expected-note @-2:26 {{of 'x'}} } From 1acecd16a37d78a153d8d479c82c6459f926f3d6 Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Fri, 4 Sep 2020 21:11:07 -0400 Subject: [PATCH 592/663] [test][IRGen] Fix check on local_extern test. Windows IR seems to include a `dso_local` annotation, which the check didn't expect and caused a failure in #33813. Added a regex check to ensure the test passes with or without the annotation. --- test/IRGen/local_extern.swift | 3 ++- test/IRGen/local_extern_windows.swift | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 test/IRGen/local_extern_windows.swift diff --git a/test/IRGen/local_extern.swift b/test/IRGen/local_extern.swift index 4ce7554681491..f60d8f1dbe9f2 100644 --- a/test/IRGen/local_extern.swift +++ b/test/IRGen/local_extern.swift @@ -1,5 +1,6 @@ +// XFAIL: OS=windows-msvc // RUN: %target-swift-frontend -import-objc-header %S/Inputs/local_extern.h %s -emit-ir | %FileCheck %s -// CHECK: @var = external global i32 +// CHECK: @var = external {{(dso_local )?}}global i32 // CHECK: @prior_var = internal global i32 // CHECK: declare i32 @func // CHECK: define internal i32 @prior_func diff --git a/test/IRGen/local_extern_windows.swift b/test/IRGen/local_extern_windows.swift new file mode 100644 index 0000000000000..23504a76804f5 --- /dev/null +++ b/test/IRGen/local_extern_windows.swift @@ -0,0 +1,10 @@ +// REQUIRES: OS=windows-msvc +// RUN: %target-swift-frontend -import-objc-header %S/Inputs/local_extern.h %s -emit-ir | %FileCheck %s +// CHECK: @var = external {{(dso_local )?}}global i32 +// CHECK: @prior_var = internal global i32 +// CHECK: define internal i32 @prior_func + +print("\(_no_prior_var())") +print("\(_no_prior_func())") +print("\(_prior_var())") +print("\(_prior_func())") From 60b7c578c4731cd76997883d1cc5b6a16ca20f50 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Fri, 4 Sep 2020 23:47:10 -0400 Subject: [PATCH 593/663] [benchmark] Add mock floating-point types for conversion benchmarks --- .../FloatingPointConversion.swift | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/benchmark/single-source/FloatingPointConversion.swift b/benchmark/single-source/FloatingPointConversion.swift index ef67b2d31c4b5..b416b8742482c 100644 --- a/benchmark/single-source/FloatingPointConversion.swift +++ b/benchmark/single-source/FloatingPointConversion.swift @@ -21,8 +21,120 @@ public let FloatingPointConversion = [ name: "ConvertFloatingPoint.GenericDoubleToDouble", runFunction: run_ConvertFloatingPoint_GenericDoubleToDouble, tags: [.validation, .api]), + BenchmarkInfo( + name: "ConvertFloatingPoint.MockFloat64ToDouble", + runFunction: run_ConvertFloatingPoint_MockFloat64ToDouble, + tags: [.validation, .api]), ] +protocol MockBinaryFloatingPoint: BinaryFloatingPoint { + associatedtype _Value: BinaryFloatingPoint + var _value: _Value { get set } + init(_ _value: _Value) +} + +extension MockBinaryFloatingPoint { + static var exponentBitCount: Int { _Value.exponentBitCount } + static var greatestFiniteMagnitude: Self { + Self(_Value.greatestFiniteMagnitude) + } + static var infinity: Self { Self(_Value.infinity) } + static var leastNonzeroMagnitude: Self { Self(_Value.leastNonzeroMagnitude) } + static var leastNormalMagnitude: Self { Self(_Value.leastNormalMagnitude) } + static var nan: Self { Self(_Value.nan) } + static var pi: Self { Self(_Value.pi) } + static var signalingNaN: Self { Self(_Value.signalingNaN) } + static var significandBitCount: Int { _Value.significandBitCount } + + static func + (lhs: Self, rhs: Self) -> Self { Self(lhs._value + rhs._value) } + static func += (lhs: inout Self, rhs: Self) { lhs._value += rhs._value } + static func - (lhs: Self, rhs: Self) -> Self { Self(lhs._value - rhs._value) } + static func -= (lhs: inout Self, rhs: Self) { lhs._value -= rhs._value } + static func * (lhs: Self, rhs: Self) -> Self { Self(lhs._value * rhs._value) } + static func *= (lhs: inout Self, rhs: Self) { lhs._value *= rhs._value } + static func / (lhs: Self, rhs: Self) -> Self { Self(lhs._value / rhs._value) } + static func /= (lhs: inout Self, rhs: Self) { lhs._value /= rhs._value } + + init(_ value: Int) { self.init(_Value(value)) } + init(_ value: Float) { self.init(_Value(value)) } + init(_ value: Double) { self.init(_Value(value)) } + init(_ value: Float80) { self.init(_Value(value)) } + init(integerLiteral value: _Value.IntegerLiteralType) { + self.init(_Value(integerLiteral: value)) + } + init(floatLiteral value: _Value.FloatLiteralType) { + self.init(_Value(floatLiteral: value)) + } + init(sign: FloatingPointSign, exponent: _Value.Exponent, significand: Self) { + self.init( + _Value(sign: sign, exponent: exponent, significand: significand._value)) + } + init( + sign: FloatingPointSign, + exponentBitPattern: _Value.RawExponent, + significandBitPattern: _Value.RawSignificand + ) { + self.init( + _Value( + sign: sign, + exponentBitPattern: exponentBitPattern, + significandBitPattern: significandBitPattern)) + } + + var binade: Self { Self(_value.binade) } + var exponent: _Value.Exponent { _value.exponent } + var exponentBitPattern: _Value.RawExponent { _value.exponentBitPattern } + var isCanonical: Bool { _value.isCanonical } + var isFinite: Bool { _value.isFinite } + var isInfinite: Bool { _value.isInfinite } + var isNaN: Bool { _value.isNaN } + var isNormal: Bool { _value.isNormal } + var isSignalingNaN: Bool { _value.isSignalingNaN } + var isSubnormal: Bool { _value.isSubnormal } + var isZero: Bool { _value.isZero } + var magnitude: Self { Self(_value.magnitude) } + var nextDown: Self { Self(_value.nextDown) } + var nextUp: Self { Self(_value.nextUp) } + var sign: FloatingPointSign { _value.sign } + var significand: Self { Self(_value.significand) } + var significandBitPattern: _Value.RawSignificand { + _value.significandBitPattern + } + var significandWidth: Int { _value.significandWidth } + var ulp: Self { Self(_value.ulp) } + + mutating func addProduct(_ lhs: Self, _ rhs: Self) { + _value.addProduct(lhs._value, rhs._value) + } + func advanced(by n: _Value.Stride) -> Self { Self(_value.advanced(by: n)) } + func distance(to other: Self) -> _Value.Stride { + _value.distance(to: other._value) + } + mutating func formRemainder(dividingBy other: Self) { + _value.formRemainder(dividingBy: other._value) + } + mutating func formSquareRoot() { _value.formSquareRoot() } + mutating func formTruncatingRemainder(dividingBy other: Self) { + _value.formTruncatingRemainder(dividingBy: other._value) + } + func isEqual(to other: Self) -> Bool { _value.isEqual(to: other._value) } + func isLess(than other: Self) -> Bool { _value.isLess(than: other._value) } + func isLessThanOrEqualTo(_ other: Self) -> Bool { + _value.isLessThanOrEqualTo(other._value) + } + mutating func round(_ rule: FloatingPointRoundingRule) { _value.round(rule) } +} + +struct MockFloat32: MockBinaryFloatingPoint { + var _value: Float + init(_ _value: Float) { self._value = _value } +} + +struct MockFloat64: MockBinaryFloatingPoint { + var _value: Double + init(_ _value: Double) { self._value = _value } +} + let doubles = [ 1.8547832857295, 26.321549267719135, 98.9544480962058, 73.70286973782363, 82.04918555938816, 76.38902969312758, 46.35647857011161, 64.0821426030317, @@ -38,6 +150,8 @@ let doubles = [ 64.79777579583545, 45.25948795832151, 94.31492354198335, 52.31096166433902, ] +let mockFloat64s = doubles.map { MockFloat64($0) } + @inline(__always) func convert< T: BinaryFloatingPoint, U: BinaryFloatingPoint @@ -64,3 +178,13 @@ public func run_ConvertFloatingPoint_GenericDoubleToDouble(_ N: Int) { } } } + +@inline(never) +public func run_ConvertFloatingPoint_MockFloat64ToDouble(_ N: Int) { + for _ in 0..<(N * 100) { + for element in mockFloat64s { + let f = Double(identity(element)) + blackHole(f) + } + } +} From 191a4f8029f87a241c9d3d0ab4b1064bbf464e12 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 4 Sep 2020 14:12:10 -0700 Subject: [PATCH 594/663] [Concurrency] Split @objc checking into a separate test file. --- test/attr/attr_objc.swift | 14 +++----------- test/attr/attr_objc_async.swift | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 test/attr/attr_objc_async.swift diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index 946e0c8c26e92..77848a0ab196a 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -1,6 +1,6 @@ -// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency -// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency | %FileCheck %s -// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency > %t.ast +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference +// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference | %FileCheck %s +// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference > %t.ast // RUN: %FileCheck -check-prefix CHECK-DUMP %s < %t.ast // REQUIRES: objc_interop @@ -2381,11 +2381,3 @@ class SR12801 { @objc subscript(foo : [T]) -> Int { return 0 } // expected-error@-1 {{subscript cannot be marked @objc because it has generic parameters}} } - -// async cannot be compiled with @objc. -class Concurrency { - @objc func doBigJob() async -> Int { return 0 } // expected-error{{'async' function cannot be represented in Objective-C}} - - @objc func takeAnAsync(_ fn: () async -> Int) { } // expected-error{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}} - // expected-note@-1{{'async' function types cannot be represented in Objective-C}} -} diff --git a/test/attr/attr_objc_async.swift b/test/attr/attr_objc_async.swift new file mode 100644 index 0000000000000..ba80dceb739c1 --- /dev/null +++ b/test/attr/attr_objc_async.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency +// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency | %FileCheck %s +// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency > %t.ast +// RUN: %FileCheck -check-prefix CHECK-DUMP %s < %t.ast +// REQUIRES: objc_interop + +// async cannot be compiled with @objc. +// CHECK-DUMP: class Concurrency +class Concurrency { + @objc func doBigJob() async -> Int { return 0 } // expected-error{{'async' function cannot be represented in Objective-C}} + + @objc func takeAnAsync(_ fn: () async -> Int) { } // expected-error{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}} + // expected-note@-1{{'async' function types cannot be represented in Objective-C}} +} From fbdd1ebf46c062f085a2dfaafb9391f302448dc3 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 4 Sep 2020 21:58:58 -0700 Subject: [PATCH 595/663] Platform: improve WinSDK modulemap to repair build The WinSDK module failed to expose WinBase properly for reuse, which the newer clang seems to object to (via an assertion). Add a separate module for WinBase which allows reuse of the definitions without causing conflicts. This caused some additional fallout requiring the creation of the WinSVC submodule (service handling, part of security and identity) and splitting up the legacy WinSock header from the WinSock2 module. This allows building Foundation again on Windows. --- stdlib/public/Platform/winsdk.modulemap | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/stdlib/public/Platform/winsdk.modulemap b/stdlib/public/Platform/winsdk.modulemap index 9baba25569167..fc0d961bd50a9 100644 --- a/stdlib/public/Platform/winsdk.modulemap +++ b/stdlib/public/Platform/winsdk.modulemap @@ -21,6 +21,10 @@ module WinSDK [system] { link "WS2_32.Lib" } + module WinSock { + header "winsock.h" + } + module core { module acl { header "AclAPI.h" @@ -206,6 +210,11 @@ module WinSDK [system] { export * } + module WinBase { + header "winbase.h" + export * + } + module WinCrypt { header "wincrypt.h" export * @@ -241,5 +250,12 @@ module WinSDK [system] { link "RpcRT4.Lib" } + + module WinSVC { + header "winsvc.h" + export * + + link "AdvAPI32.Lib" + } } From 713b57becbceeee7f20c23716db134f244931dd0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 4 Sep 2020 22:04:12 -0400 Subject: [PATCH 596/663] Frontend: Remove -lazy-astscopes flag --- include/swift/Basic/LangOptions.h | 3 --- include/swift/Option/FrontendOptions.td | 3 --- lib/AST/ASTScopeCreation.cpp | 25 +++++++++++-------------- lib/AST/ASTScopeSourceRange.cpp | 2 -- lib/Frontend/CompilerInvocation.cpp | 1 - 5 files changed, 11 insertions(+), 23 deletions(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index a05d65611801b..6810676539819 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -254,9 +254,6 @@ namespace swift { /// Should we stress ASTScope-based resolution for debugging? bool StressASTScopeLookup = false; - /// Build the ASTScope tree lazily - bool LazyASTScopes = true; - /// Whether to enable the new operator decl and precedencegroup lookup /// behavior. This is a staging flag, and will be removed in the future. bool EnableNewOperatorLookup = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 82d904206c720..cf788d081253d 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -160,9 +160,6 @@ def crosscheck_unqualified_lookup : Flag<["-"], "crosscheck-unqualified-lookup"> def stress_astscope_lookup : Flag<["-"], "stress-astscope-lookup">, HelpText<"Stress ASTScope-based unqualified name lookup (for testing)">; -def lazy_astscopes : Flag<["-"], "lazy-astscopes">, - HelpText<"Build ASTScopes lazily">; - def use_clang_function_types : Flag<["-"], "use-clang-function-types">, HelpText<"Use stored Clang function types for computing canonical types.">; diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 558287ddd458a..d2818027ef2b2 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -354,10 +354,10 @@ class ScopeCreator final { ASTScopeImpl *constructExpandAndInsert(ASTScopeImpl *parent, Args... args) { auto *child = new (ctx) Scope(args...); parent->addChild(child, ctx); - if (shouldBeLazy()) { - if (auto *ip = child->insertionPointForDeferredExpansion().getPtrOrNull()) - return ip; - } + + if (auto *ip = child->insertionPointForDeferredExpansion().getPtrOrNull()) + return ip; + ASTScopeImpl *insertionPoint = child->expandAndBeCurrentDetectingRecursion(*this); ASTScopeAssert(child->verifyThatThisNodeComeAfterItsPriorSibling(), @@ -646,8 +646,6 @@ class ScopeCreator final { return !n.isDecl(DeclKind::Var); } - bool shouldBeLazy() const { return ctx.LangOpts.LazyASTScopes; } - public: /// For debugging. Return true if scope tree contains all the decl contexts in /// the AST May modify the scope tree in order to update obsolete scopes. @@ -1121,14 +1119,13 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) { disownDescendants(scopeCreator); auto *insertionPoint = expandSpecifically(scopeCreator); - if (scopeCreator.shouldBeLazy()) { - ASTScopeAssert(!insertionPointForDeferredExpansion() || - insertionPointForDeferredExpansion().get() == - insertionPoint, - "In order for lookups into lazily-expanded scopes to be " - "accurate before expansion, the insertion point before " - "expansion must be the same as after expansion."); - } + ASTScopeAssert(!insertionPointForDeferredExpansion() || + insertionPointForDeferredExpansion().get() == + insertionPoint, + "In order for lookups into lazily-expanded scopes to be " + "accurate before expansion, the insertion point before " + "expansion must be the same as after expansion."); + replaceASTAncestorScopes(astAncestorScopes); setWasExpanded(); beCurrent(); diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index cecd970590cc6..87713befcfcb2 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -526,8 +526,6 @@ void ASTScopeImpl::computeAndCacheSourceRangeOfScope( } bool ASTScopeImpl::checkLazySourceRange(const ASTContext &ctx) const { - if (!ctx.LangOpts.LazyASTScopes) - return true; const auto unexpandedRange = sourceRangeForDeferredExpansion(); const auto expandedRange = computeSourceRangeOfScopeWithChildASTNodes(); if (unexpandedRange.isInvalid() || expandedRange.isInvalid()) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 3f6468b95bad9..eab504f229858 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -444,7 +444,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.DisableParserLookup |= Args.hasArg(OPT_disable_parser_lookup); Opts.StressASTScopeLookup |= Args.hasArg(OPT_stress_astscope_lookup); - Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes); Opts.EnableNewOperatorLookup = Args.hasFlag(OPT_enable_new_operator_lookup, OPT_disable_new_operator_lookup, /*default*/ false); From b82c57a800ddd568e9b8131323f7f4ca6691d3ee Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Thu, 3 Sep 2020 23:18:53 -0400 Subject: [PATCH 597/663] [Sema] Require function builders to have at least one buildBlock method If the supplied method is not static, offer a fix-it to make it static --- include/swift/AST/DiagnosticsSema.def | 10 ++ lib/Sema/BuilderTransform.cpp | 62 +++++++------ lib/Sema/TypeCheckAttr.cpp | 28 +++++- lib/Sema/TypeChecker.h | 7 ++ test/IDE/print_swift_module.swift | 4 +- test/decl/var/function_builders.swift | 128 +++++++++++++++++++++++++- 6 files changed, 205 insertions(+), 34 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 7977c030ba0c6..8f56002813d0e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -5250,6 +5250,16 @@ WARNING(function_builder_missing_limited_availability, none, "function builder %0 does not implement 'buildLimitedAvailability'; " "this code may crash on earlier versions of the OS", (Type)) +ERROR(function_builder_static_buildblock, none, + "function builder must provide at least one static 'buildBlock' " + "method", ()) +NOTE(function_builder_non_static_buildblock, none, + "did you mean to make instance method 'buildBlock' static?", ()) +NOTE(function_builder_buildblock_enum_case, none, + "enum case 'buildBlock' cannot be used to satisfy the function builder " + "requirement", ()) +NOTE(function_builder_buildblock_not_static_method, none, + "potential match 'buildBlock' is not a static method", ()) //------------------------------------------------------------------------------ // MARK: Tuple Shuffle Diagnostics diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index acb8d8881c658..4ae60b1194ba8 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -145,32 +145,8 @@ class BuilderClosureVisitor return known->second; } - bool found = false; - SmallVector foundDecls; - dc->lookupQualified( - builderType, DeclNameRef(fnName), - NL_QualifiedDefault | NL_ProtocolMembers, foundDecls); - for (auto decl : foundDecls) { - if (auto func = dyn_cast(decl)) { - // Function must be static. - if (!func->isStatic()) - continue; - - // Function must have the right argument labels, if provided. - if (!argLabels.empty()) { - auto funcLabels = func->getName().getArgumentNames(); - if (argLabels.size() > funcLabels.size() || - funcLabels.slice(0, argLabels.size()) != argLabels) - continue; - } - - // Okay, it's a good-enough match. - found = true; - break; - } - } - - return supportedOps[fnName] = found; + return supportedOps[fnName] = TypeChecker::typeSupportsBuilderOp( + builderType, dc, fnName, argLabels); } /// Build an implicit variable in this context. @@ -1874,3 +1850,37 @@ std::vector TypeChecker::findReturnStatements(AnyFunctionRef fn) { (void)precheck.run(); return precheck.getReturnStmts(); } + +bool TypeChecker::typeSupportsBuilderOp( + Type builderType, DeclContext *dc, Identifier fnName, + ArrayRef argLabels, SmallVectorImpl *allResults) { + bool foundMatch = false; + SmallVector foundDecls; + dc->lookupQualified( + builderType, DeclNameRef(fnName), + NL_QualifiedDefault | NL_ProtocolMembers, foundDecls); + for (auto decl : foundDecls) { + if (auto func = dyn_cast(decl)) { + // Function must be static. + if (!func->isStatic()) + continue; + + // Function must have the right argument labels, if provided. + if (!argLabels.empty()) { + auto funcLabels = func->getName().getArgumentNames(); + if (argLabels.size() > funcLabels.size() || + funcLabels.slice(0, argLabels.size()) != argLabels) + continue; + } + + foundMatch = true; + break; + } + } + + if (allResults) + allResults->append(foundDecls.begin(), foundDecls.end()); + + return foundMatch; +} + diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index df4080e85a1ba..785cecc89f90d 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -3008,8 +3008,32 @@ void AttributeChecker::visitPropertyWrapperAttr(PropertyWrapperAttr *attr) { } void AttributeChecker::visitFunctionBuilderAttr(FunctionBuilderAttr *attr) { - // TODO: check that the type at least provides a `sequence` factory? - // Any other validation? + auto *nominal = dyn_cast(D); + SmallVector potentialMatches; + bool supportsBuildBlock = TypeChecker::typeSupportsBuilderOp( + nominal->getDeclaredType(), nominal, D->getASTContext().Id_buildBlock, + /*argLabels=*/{}, &potentialMatches); + + if (!supportsBuildBlock) { + diagnose(nominal->getLoc(), diag::function_builder_static_buildblock); + + // For any close matches, attempt to explain to the user why they aren't + // valid. + for (auto *member : potentialMatches) { + if (member->isStatic() && isa(member)) + continue; + + if (isa(member) && + member->getDeclContext()->getSelfNominalTypeDecl() == nominal) + diagnose(member->getLoc(), diag::function_builder_non_static_buildblock) + .fixItInsert(member->getAttributeInsertionLoc(true), "static "); + else if (isa(member)) + diagnose(member->getLoc(), diag::function_builder_buildblock_enum_case); + else + diagnose(member->getLoc(), + diag::function_builder_buildblock_not_static_method); + } + } } void diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 9881b477ddd38..ad0c427c4d564 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1221,6 +1221,13 @@ bool requireArrayLiteralIntrinsics(ASTContext &ctx, SourceLoc loc); /// If \c expr is not part of a member chain or the base is something other than /// an \c UnresolvedMemberExpr, \c nullptr is returned. UnresolvedMemberExpr *getUnresolvedMemberChainBase(Expr *expr); + +/// Checks whether a function builder type has a well-formed function builder +/// method with the given name. If provided and non-empty, the argument labels +/// are verified against any candidates. +bool typeSupportsBuilderOp(Type builderType, DeclContext *dc, Identifier fnName, + ArrayRef argLabels = {}, + SmallVectorImpl *allResults = nullptr); }; // namespace TypeChecker /// Temporary on-stack storage and unescaping for encoded diagnostic diff --git a/test/IDE/print_swift_module.swift b/test/IDE/print_swift_module.swift index 63e4a9d54aa55..a54c31fa390b3 100644 --- a/test/IDE/print_swift_module.swift +++ b/test/IDE/print_swift_module.swift @@ -28,7 +28,9 @@ public func returnsAlias() -> Alias { } @_functionBuilder -struct BridgeBuilder {} +struct BridgeBuilder { + static func buildBlock(_: Any...) {} +} public struct City { public init(@BridgeBuilder builder: () -> ()) {} diff --git a/test/decl/var/function_builders.swift b/test/decl/var/function_builders.swift index fd93eaf42cc9b..b3b860535f1cc 100644 --- a/test/decl/var/function_builders.swift +++ b/test/decl/var/function_builders.swift @@ -7,10 +7,10 @@ var globalBuilder: Int func globalBuilderFunction() -> Int { return 0 } @_functionBuilder -struct Maker {} +struct Maker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} @_functionBuilder -class Inventor {} +class Inventor {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} @Maker // expected-error {{function builder attribute 'Maker' can only be applied to a parameter, function, or computed property}} typealias typename = Inventor @@ -66,11 +66,11 @@ func makerParamAutoclosure(@Maker // expected-error {{function builder attribute fn: @autoclosure () -> ()) {} @_functionBuilder -struct GenericMaker {} // expected-note {{generic type 'GenericMaker' declared here}} +struct GenericMaker {} // expected-note {{generic type 'GenericMaker' declared here}} expected-error {{function builder must provide at least one static 'buildBlock' method}} struct GenericContainer { // expected-note {{generic type 'GenericContainer' declared here}} @_functionBuilder - struct Maker {} + struct Maker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} } func makeParamUnbound(@GenericMaker // expected-error {{reference to generic type 'GenericMaker' requires arguments}} @@ -89,7 +89,7 @@ func makeParamNestedBound(@GenericContainer.Maker protocol P { } @_functionBuilder -struct ConstrainedGenericMaker {} +struct ConstrainedGenericMaker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} struct WithinGeneric { @@ -99,3 +99,121 @@ struct WithinGeneric { func makeParamBoundInContextBad(@ConstrainedGenericMaker fn: () -> ()) {} } + +@_functionBuilder +struct ValidBuilder1 { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +protocol BuilderFuncHelper {} + +extension BuilderFuncHelper { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +struct ValidBuilder2: BuilderFuncHelper {} + +class BuilderFuncBase { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +class ValidBuilder3: BuilderFuncBase {} + +@_functionBuilder +struct ValidBuilder4 {} +extension ValidBuilder4 { + static func buildBlock(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +struct ValidBuilder5 { + static func buildBlock() -> Int { 0 } +} + +@_functionBuilder +struct InvalidBuilder1 {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +@_functionBuilder +struct InvalidBuilder2 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + func buildBlock(_ exprs: Any...) -> Int { return exprs.count } // expected-note {{did you mean to make instance method 'buildBlock' static?}} {{3-3=static }} +} + +@_functionBuilder +struct InvalidBuilder3 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + var buildBlock: (Any...) -> Int = { return $0.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +struct InvalidBuilder4 {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} +extension InvalidBuilder4 { + func buildBlock(_ exprs: Any...) -> Int { return exprs.count } // expected-note {{did you mean to make instance method 'buildBlock' static?}} {{3-3=static }} +} + +protocol InvalidBuilderHelper {} +extension InvalidBuilderHelper { + func buildBlock(_ exprs: Any...) -> Int { return exprs.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +struct InvalidBuilder5: InvalidBuilderHelper {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +@_functionBuilder +struct InvalidBuilder6 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + static var buildBlock: Int = 0 // expected-note {{potential match 'buildBlock' is not a static method}} +} + +struct Callable { + func callAsFunction(_ exprs: Any...) -> Int { return exprs.count } +} + +@_functionBuilder +struct InvalidBuilder7 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + static var buildBlock = Callable() // expected-note {{potential match 'buildBlock' is not a static method}} +} + +class BuilderVarBase { + static var buildBlock: (Any...) -> Int = { return $0.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +class InvalidBuilder8: BuilderVarBase {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +protocol BuilderVarHelper {} + +extension BuilderVarHelper { + static var buildBlock: (Any...) -> Int { { return $0.count } } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +struct InvalidBuilder9: BuilderVarHelper {} // expected-error {{function builder must provide at least one static 'buildBlock' method}} + +@_functionBuilder +struct InvalidBuilder10 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + static var buildBlock: (Any...) -> Int = { return $0.count } // expected-note {{potential match 'buildBlock' is not a static method}} +} + +@_functionBuilder +enum InvalidBuilder11 { // expected-error {{function builder must provide at least one static 'buildBlock' method}} + case buildBlock(Any) // expected-note {{enum case 'buildBlock' cannot be used to satisfy the function builder requirement}} +} + +struct S { + @ValidBuilder1 var v1: Int { 1 } + @ValidBuilder2 var v2: Int { 1 } + @ValidBuilder3 var v3: Int { 1 } + @ValidBuilder4 var v4: Int { 1 } + @ValidBuilder5 func v5() -> Int {} + @InvalidBuilder1 var i1: Int { 1 } // expected-error {{type 'InvalidBuilder1' has no member 'buildBlock'}} + @InvalidBuilder2 var i2: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder2'; did you mean to use a value of this type instead?}} + @InvalidBuilder3 var i3: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder3'; did you mean to use a value of this type instead?}} + @InvalidBuilder4 var i4: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder4'; did you mean to use a value of this type instead?}} + @InvalidBuilder5 var i5: Int { 1 } // expected-error {{instance member 'buildBlock' cannot be used on type 'InvalidBuilder5'; did you mean to use a value of this type instead?}} + @InvalidBuilder6 var i6: Int { 1 } // expected-error {{cannot call value of non-function type 'Int'}} + @InvalidBuilder7 var i7: Int { 1 } + @InvalidBuilder8 var i8: Int { 1 } + @InvalidBuilder9 var i9: Int { 1 } + @InvalidBuilder10 var i10: Int { 1 } + @InvalidBuilder11 var i11: InvalidBuilder11 { 1 } +} From c89b5ac01b15b6385493ba7963f6864232c7c382 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 4 Sep 2020 22:50:42 -0700 Subject: [PATCH 598/663] [serialization] Rename ResultVal -> ResultInst. This is a misnomer from when SILInstructions were always single valued. NFC. --- lib/Serialization/DeserializeSIL.cpp | 383 +++++++++++++-------------- 1 file changed, 184 insertions(+), 199 deletions(-) diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index b4c536e4f7355..b3024b0939170 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -1179,7 +1179,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, // FIXME: validate SILInstructionKind OpCode = (SILInstructionKind) RawOpCode; - SILInstruction *ResultVal; + SILInstruction *ResultInst; switch (OpCode) { case SILInstructionKind::DebugValueInst: case SILInstructionKind::DebugValueAddrInst: @@ -1187,19 +1187,19 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::AllocBoxInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createAllocBox(Loc, - cast(MF->getType(TyID)->getCanonicalType()), - None, /*bool hasDynamicLifetime*/ Attr != 0); + ResultInst = Builder.createAllocBox( + Loc, cast(MF->getType(TyID)->getCanonicalType()), None, + /*bool hasDynamicLifetime*/ Attr != 0); break; case SILInstructionKind::AllocStackInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createAllocStack( + ResultInst = Builder.createAllocStack( Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), None, /*bool hasDynamicLifetime*/ Attr != 0); break; case SILInstructionKind::MetatypeInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createMetatype( + ResultInst = Builder.createMetatype( Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); break; @@ -1207,7 +1207,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ "Layout should be OneTypeOneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), \ getLocalValue(ValID, getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2, Fn))); \ @@ -1222,7 +1222,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DeallocBoxInst: assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createDeallocBox( + ResultInst = Builder.createDeallocBox( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn))); @@ -1230,7 +1230,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::OpenExistentialAddrInst: assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createOpenExistentialAddr( + ResultInst = Builder.createOpenExistentialAddr( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1243,7 +1243,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ "Layout should be OneTypeOneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, \ getLocalValue(ValID, getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2, Fn)), \ @@ -1283,7 +1283,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::ProjectBoxInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createProjectBox( + ResultInst = Builder.createProjectBox( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1294,7 +1294,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); bool isLifetimeGuaranteed = Attr & 0x01; - ResultVal = Builder.createConvertEscapeToNoEscape( + ResultInst = Builder.createConvertEscapeToNoEscape( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1306,7 +1306,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); bool withoutActuallyEscaping = Attr & 0x01; - ResultVal = Builder.createConvertFunction( + ResultInst = Builder.createConvertFunction( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -1319,18 +1319,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, "Layout should be OneTypeOneOperand."); bool isStrict = Attr & 0x01; bool isInvariant = Attr & 0x02; - ResultVal = Builder.createPointerToAddress( + ResultInst = Builder.createPointerToAddress( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), isStrict, - isInvariant); + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), + isStrict, isInvariant); break; } case SILInstructionKind::DeallocExistentialBoxInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createDeallocExistentialBox( + ResultInst = Builder.createDeallocExistentialBox( Loc, MF->getType(TyID)->getCanonicalType(), getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn))); @@ -1345,15 +1345,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto BitsTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn); auto Bits = getLocalValue(ValID2, BitsTy); - - ResultVal = Builder.createRefToBridgeObject(Loc, Ref, Bits); + + ResultInst = Builder.createRefToBridgeObject(Loc, Ref, Bits); break; } case SILInstructionKind::ObjCProtocolInst: { auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Proto = MF->getDecl(ValID); - ResultVal = Builder.createObjCProtocol(Loc, cast(Proto), Ty); + ResultInst = Builder.createObjCProtocol(Loc, cast(Proto), Ty); break; } @@ -1384,28 +1384,24 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, switch (OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::InitExistentialAddrInst: - ResultVal = Builder.createInitExistentialAddr(Loc, operand, - ConcreteTy, - Ty, - ctxConformances); + ResultInst = Builder.createInitExistentialAddr(Loc, operand, ConcreteTy, + Ty, ctxConformances); break; case SILInstructionKind::InitExistentialValueInst: - ResultVal = Builder.createInitExistentialValue(Loc, Ty, ConcreteTy, + ResultInst = Builder.createInitExistentialValue(Loc, Ty, ConcreteTy, operand, ctxConformances); break; case SILInstructionKind::InitExistentialMetatypeInst: - ResultVal = Builder.createInitExistentialMetatype(Loc, operand, Ty, - ctxConformances); + ResultInst = Builder.createInitExistentialMetatype(Loc, operand, Ty, + ctxConformances); break; case SILInstructionKind::InitExistentialRefInst: - ResultVal = Builder.createInitExistentialRef(Loc, Ty, - ConcreteTy, - operand, - ctxConformances); + ResultInst = Builder.createInitExistentialRef(Loc, Ty, ConcreteTy, + operand, ctxConformances); break; case SILInstructionKind::AllocExistentialBoxInst: - ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy, - ctxConformances); + ResultInst = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy, + ctxConformances); break; } break; @@ -1439,12 +1435,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType MetadataType = getSILType(MF->getType(ListOfValues[i+1]), SILValueCategory::Object, Fn); SILValue MetadataOp = getLocalValue(ListOfValues[i], MetadataType); - ResultVal = Builder.createAllocRefDynamic(Loc, MetadataOp, ClassTy, - isObjC, TailTypes, Counts); + ResultInst = Builder.createAllocRefDynamic(Loc, MetadataOp, ClassTy, + isObjC, TailTypes, Counts); } else { assert(i == NumVals); - ResultVal = Builder.createAllocRef(Loc, ClassTy, isObjC, canAllocOnStack, - TailTypes, Counts); + ResultInst = Builder.createAllocRef(Loc, ClassTy, isObjC, canAllocOnStack, + TailTypes, Counts); } break; } @@ -1469,13 +1465,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); if (OpCode == SILInstructionKind::ApplyInst) { - ResultVal = Builder.createApply(Loc, getLocalValue(ValID, FnTy), - Substitutions, Args, - IsNonThrowingApply != 0); + ResultInst = + Builder.createApply(Loc, getLocalValue(ValID, FnTy), Substitutions, + Args, IsNonThrowingApply != 0); } else { - ResultVal = Builder.createBeginApply(Loc, getLocalValue(ValID, FnTy), - Substitutions, Args, - IsNonThrowingApply != 0); + ResultInst = Builder.createBeginApply(Loc, getLocalValue(ValID, FnTy), + Substitutions, Args, + IsNonThrowingApply != 0); } break; } @@ -1505,9 +1501,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, I, Builder.getTypeExpansionContext()))); SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); - ResultVal = Builder.createTryApply(Loc, getLocalValue(ValID, FnTy), - Substitutions, Args, normalBB, - errorBB); + ResultInst = Builder.createTryApply(Loc, getLocalValue(ValID, FnTy), + Substitutions, Args, normalBB, errorBB); break; } case SILInstructionKind::PartialApplyInst: { @@ -1541,7 +1536,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ? PartialApplyInst::OnStackKind::OnStack : PartialApplyInst::OnStackKind::NotOnStack; // FIXME: Why the arbitrary order difference in IRBuilder type argument? - ResultVal = Builder.createPartialApply( + ResultInst = Builder.createPartialApply( Loc, FnVal, Substitutions, Args, closureTy.castTo()->getCalleeConvention(), onStack); break; @@ -1558,9 +1553,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, } SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); Identifier Name = MF->getIdentifier(ValID); - - ResultVal = Builder.createBuiltin(Loc, Name, ResultTy, Substitutions, - Args); + + ResultInst = + Builder.createBuiltin(Loc, Name, ResultTy, Substitutions, Args); break; } case SILInstructionKind::AllocGlobalInst: { @@ -1571,7 +1566,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILGlobalVariable *g = getGlobalForReference(Name); assert(g && "Can't deserialize global variable"); - ResultVal = Builder.createAllocGlobal(Loc, g); + ResultInst = Builder.createAllocGlobal(Loc, g); break; } case SILInstructionKind::GlobalAddrInst: @@ -1593,20 +1588,20 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, (void)Ty; (void)expectedType; if (OpCode == SILInstructionKind::GlobalAddrInst) { - ResultVal = Builder.createGlobalAddr(Loc, g); + ResultInst = Builder.createGlobalAddr(Loc, g); } else { - ResultVal = Builder.createGlobalValue(Loc, g); + ResultInst = Builder.createGlobalValue(Loc, g); } break; } case SILInstructionKind::BaseAddrForOffsetInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createBaseAddrForOffset(Loc, - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); + ResultInst = Builder.createBaseAddrForOffset( + Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); break; case SILInstructionKind::DeallocStackInst: { auto Ty = MF->getType(TyID); - ResultVal = Builder.createDeallocStack( + ResultInst = Builder.createDeallocStack( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn))); break; @@ -1614,7 +1609,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DeallocRefInst: { auto Ty = MF->getType(TyID); bool OnStack = (bool)Attr; - ResultVal = Builder.createDeallocRef( + ResultInst = Builder.createDeallocRef( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), OnStack); @@ -1623,17 +1618,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DeallocPartialRefInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createDeallocPartialRef(Loc, - getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory, Fn)), + ResultInst = Builder.createDeallocPartialRef( + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, - getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); + getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::FunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); - ResultVal = Builder.createFunctionRef( + ResultInst = Builder.createFunctionRef( Loc, getFuncForReference( FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); @@ -1642,7 +1637,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::DynamicFunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); - ResultVal = Builder.createDynamicFunctionRef( + ResultInst = Builder.createDynamicFunctionRef( Loc, getFuncForReference( FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); @@ -1651,7 +1646,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::PreviousDynamicFunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); - ResultVal = Builder.createPreviousDynamicFunctionRef( + ResultInst = Builder.createPreviousDynamicFunctionRef( Loc, getFuncForReference( FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); @@ -1660,7 +1655,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::MarkDependenceInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createMarkDependence( + ResultInst = Builder.createMarkDependence( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1670,7 +1665,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::CopyBlockWithoutEscapingInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createCopyBlockWithoutEscaping( + ResultInst = Builder.createCopyBlockWithoutEscaping( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1680,7 +1675,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::IndexAddrInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createIndexAddr( + ResultInst = Builder.createIndexAddr( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1691,7 +1686,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); auto ResultTy = MF->getType(TyID3); - ResultVal = Builder.createTailAddr( + ResultInst = Builder.createTailAddr( Loc, getLocalValue(ValID, getSILType(Ty, SILValueCategory::Address, Fn)), getLocalValue(ValID2, getSILType(Ty2, SILValueCategory::Object, Fn)), @@ -1701,7 +1696,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::IndexRawPointerInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createIndexRawPointer( + ResultInst = Builder.createIndexRawPointer( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, @@ -1715,7 +1710,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, bool negate = text[0] == '-'; if (negate) text = text.drop_front(); APInt value = intTy->getWidth().parse(text, 10, negate); - ResultVal = Builder.createIntegerLiteral( + ResultInst = Builder.createIntegerLiteral( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value); break; } @@ -1730,7 +1725,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, APFloat value(floatTy->getAPFloatSemantics(), bits); - ResultVal = Builder.createFloatLiteral( + ResultInst = Builder.createFloatLiteral( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value); break; } @@ -1738,15 +1733,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, StringRef StringVal = MF->getIdentifierText(ValID); auto encoding = fromStableStringEncoding(Attr); if (!encoding) return true; - ResultVal = Builder.createStringLiteral(Loc, StringVal, - encoding.getValue()); + ResultInst = + Builder.createStringLiteral(Loc, StringVal, encoding.getValue()); break; } case SILInstructionKind::CondFailInst: { SILValue Op = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); StringRef StringVal = MF->getIdentifierText(ValID2); - ResultVal = Builder.createCondFail(Loc, Op, StringVal); + ResultInst = Builder.createCondFail(Loc, Op, StringVal); break; } case SILInstructionKind::MarkFunctionEscapeInst: { @@ -1759,7 +1754,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ListOfValues[I + 2], getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn))); } - ResultVal = Builder.createMarkFunctionEscape(Loc, OpList); + ResultInst = Builder.createMarkFunctionEscape(Loc, OpList); break; } // Checked Conversion instructions. @@ -1772,7 +1767,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); CanType targetFormalType = MF->getType(ListOfValues[3])->getCanonicalType(); - ResultVal = Builder.createUnconditionalCheckedCast( + ResultInst = Builder.createUnconditionalCheckedCast( Loc, src, targetLoweredType, targetFormalType); break; } @@ -1780,7 +1775,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, #define UNARY_INSTRUCTION(ID) \ case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, \ getLocalValue(ValID, getSILType(MF->getType(TyID), \ (SILValueCategory)TyCategory, Fn))); \ @@ -1789,7 +1784,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, #define REFCOUNTING_INSTRUCTION(ID) \ case SILInstructionKind::ID##Inst: \ assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); \ - ResultVal = Builder.create##ID( \ + ResultInst = Builder.create##ID( \ Loc, \ getLocalValue(ValID, getSILType(MF->getType(TyID), \ (SILValueCategory)TyCategory, Fn)), \ @@ -1839,7 +1834,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::IsEscapingClosureInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); unsigned verificationType = Attr; - ResultVal = Builder.createIsEscapingClosure( + ResultInst = Builder.createIsEscapingClosure( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)), @@ -1850,10 +1845,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::BeginCOWMutationInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); unsigned isNative = Attr; - ResultVal = Builder.createBeginCOWMutation( + ResultInst = Builder.createBeginCOWMutation( Loc, - getLocalValue(ValID, - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)), + getLocalValue(ValID, getSILType(MF->getType(TyID), + (SILValueCategory)TyCategory, Fn)), isNative != 0); break; } @@ -1861,7 +1856,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::EndCOWMutationInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); unsigned keepUnique = Attr; - ResultVal = Builder.createEndCOWMutation( + ResultInst = Builder.createEndCOWMutation( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)), @@ -1873,20 +1868,20 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); SILValue Operand = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); - ResultVal = Builder.createDestructureTuple(Loc, Operand); + ResultInst = Builder.createDestructureTuple(Loc, Operand); break; } case SILInstructionKind::DestructureStructInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); SILValue Operand = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); - ResultVal = Builder.createDestructureStruct(Loc, Operand); + ResultInst = Builder.createDestructureStruct(Loc, Operand); break; } case SILInstructionKind::UncheckedOwnershipConversionInst: { auto Ty = MF->getType(TyID); auto ResultKind = ValueOwnershipKind(Attr); - ResultVal = Builder.createUncheckedOwnershipConversion( + ResultInst = Builder.createUncheckedOwnershipConversion( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), ResultKind); @@ -1896,7 +1891,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, case SILInstructionKind::LoadInst: { auto Ty = MF->getType(TyID); auto Qualifier = LoadOwnershipQualifier(Attr); - ResultVal = Builder.createLoad( + ResultInst = Builder.createLoad( Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), Qualifier); @@ -1909,7 +1904,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, bool isTake = (Attr > 0); \ auto Val = getLocalValue( \ ValID, getSILType(Ty, SILValueCategory(TyCategory), Fn)); \ - ResultVal = Builder.createLoad##Name(Loc, Val, IsTake_t(isTake)); \ + ResultInst = Builder.createLoad##Name(Loc, Val, IsTake_t(isTake)); \ break; \ } \ case SILInstructionKind::Store##Name##Inst: { \ @@ -1918,9 +1913,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto refType = addrType.castTo(); \ auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); \ bool isInit = (Attr > 0); \ - ResultVal = Builder.createStore##Name(Loc, getLocalValue(ValID, ValType), \ - getLocalValue(ValID2, addrType), \ - IsInitialization_t(isInit)); \ + ResultInst = Builder.createStore##Name(Loc, getLocalValue(ValID, ValType), \ + getLocalValue(ValID2, addrType), \ + IsInitialization_t(isInit)); \ break; \ } #include "swift/AST/ReferenceStorage.def" @@ -1928,7 +1923,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Kind = (MarkUninitializedInst::Kind)Attr; auto Val = getLocalValue(ValID, Ty); - ResultVal = Builder.createMarkUninitialized(Loc, Val, Kind); + ResultInst = Builder.createMarkUninitialized(Loc, Val, Kind); break; } case SILInstructionKind::StoreInst: { @@ -1936,16 +1931,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType ValType = addrType.getObjectType(); auto Qualifier = StoreOwnershipQualifier(Attr); - ResultVal = Builder.createStore(Loc, getLocalValue(ValID, ValType), - getLocalValue(ValID2, addrType), Qualifier); + ResultInst = + Builder.createStore(Loc, getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType), Qualifier); break; } case SILInstructionKind::StoreBorrowInst: { auto Ty = MF->getType(TyID); SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType ValType = addrType.getObjectType(); - ResultVal = Builder.createStoreBorrow(Loc, getLocalValue(ValID, ValType), - getLocalValue(ValID2, addrType)); + ResultInst = Builder.createStoreBorrow(Loc, getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType)); break; } case SILInstructionKind::BeginAccessInst: { @@ -1955,16 +1951,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x3); bool noNestedConflict = (Attr >> 4) & 0x01; bool fromBuiltin = (Attr >> 5) & 0x01; - ResultVal = - Builder.createBeginAccess(Loc, op, accessKind, enforcement, - noNestedConflict, fromBuiltin); + ResultInst = Builder.createBeginAccess(Loc, op, accessKind, enforcement, + noNestedConflict, fromBuiltin); break; } case SILInstructionKind::EndAccessInst: { SILValue op = getLocalValue( ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); bool aborted = Attr & 0x1; - ResultVal = Builder.createEndAccess(Loc, op, aborted); + ResultInst = Builder.createEndAccess(Loc, op, aborted); break; } case SILInstructionKind::BeginUnpairedAccessInst: { @@ -1977,9 +1972,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x03); bool noNestedConflict = (Attr >> 4) & 0x01; bool fromBuiltin = (Attr >> 5) & 0x01; - ResultVal = Builder.createBeginUnpairedAccess( - Loc, source, buffer, accessKind, enforcement, noNestedConflict, - fromBuiltin); + ResultInst = Builder.createBeginUnpairedAccess( + Loc, source, buffer, accessKind, enforcement, noNestedConflict, + fromBuiltin); break; } case SILInstructionKind::EndUnpairedAccessInst: { @@ -1988,8 +1983,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, bool aborted = Attr & 0x1; auto enforcement = SILAccessEnforcement((Attr >> 1) & 0x03); bool fromBuiltin = (Attr >> 3) & 0x01; - ResultVal = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted, - fromBuiltin); + ResultInst = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted, + fromBuiltin); break; } case SILInstructionKind::CopyAddrInst: { @@ -1997,11 +1992,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); bool isInit = (Attr & 0x2) > 0; bool isTake = (Attr & 0x1) > 0; - ResultVal = Builder.createCopyAddr(Loc, - getLocalValue(ValID, addrType), - getLocalValue(ValID2, addrType), - IsTake_t(isTake), - IsInitialization_t(isInit)); + ResultInst = Builder.createCopyAddr( + Loc, getLocalValue(ValID, addrType), getLocalValue(ValID2, addrType), + IsTake_t(isTake), IsInitialization_t(isInit)); break; } case SILInstructionKind::AssignInst: { @@ -2009,10 +2002,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType valType = addrType.getObjectType(); auto qualifier = AssignOwnershipQualifier(Attr); - ResultVal = Builder.createAssign(Loc, - getLocalValue(ValID, valType), - getLocalValue(ValID2, addrType), - qualifier); + ResultInst = + Builder.createAssign(Loc, getLocalValue(ValID, valType), + getLocalValue(ValID2, addrType), qualifier); break; } case SILInstructionKind::AssignByWrapperInst: @@ -2021,7 +2013,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, assert(RecordKind == SIL_ONE_TYPE_VALUES && "Layout should be OneTypeValues."); auto Ty = MF->getType(TyID); // BoundTy - ResultVal = Builder.createBindMemory( + ResultInst = Builder.createBindMemory( Loc, getLocalValue(ListOfValues[2], getSILType(MF->getType(ListOfValues[0]), @@ -2042,11 +2034,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto ResultTy = Val->getType().getFieldType( Field, SILMod, Builder.getTypeExpansionContext()); if (OpCode == SILInstructionKind::StructElementAddrInst) - ResultVal = Builder.createStructElementAddr(Loc, Val, Field, - ResultTy.getAddressType()); + ResultInst = Builder.createStructElementAddr(Loc, Val, Field, + ResultTy.getAddressType()); else - ResultVal = Builder.createStructExtract(Loc, Val, Field, - ResultTy.getObjectType()); + ResultInst = Builder.createStructExtract(Loc, Val, Field, + ResultTy.getObjectType()); break; } case SILInstructionKind::StructInst: { @@ -2060,7 +2052,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ListOfValues[I + 2], getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn))); } - ResultVal = Builder.createStruct( + ResultInst = Builder.createStruct( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList); break; } @@ -2075,12 +2067,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, switch (OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::TupleElementAddrInst: - ResultVal = Builder.createTupleElementAddr( + ResultInst = Builder.createTupleElementAddr( Loc, getLocalValue(ValID, ST), TyID, getSILType(ResultTy, SILValueCategory::Address, Fn)); break; case SILInstructionKind::TupleExtractInst: - ResultVal = Builder.createTupleExtract( + ResultInst = Builder.createTupleExtract( Loc, getLocalValue(ValID, ST), TyID, getSILType(ResultTy, SILValueCategory::Object, Fn)); break; @@ -2100,7 +2092,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getLocalValue(ListOfValues[I], getSILType(EltTy, SILValueCategory::Object, Fn))); } - ResultVal = Builder.createTuple( + ResultInst = Builder.createTuple( Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList); break; } @@ -2119,7 +2111,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILValue elementVal = getLocalValue(ListOfValues[i], elementType); elements.push_back(elementVal); } - ResultVal = Builder.createObject(Loc, ClassTy, elements, numBaseElements); + ResultInst = Builder.createObject(Loc, ClassTy, elements, numBaseElements); break; } case SILInstructionKind::BranchInst: { @@ -2130,8 +2122,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I + 1], Fn))); - ResultVal = Builder.createBranch(Loc, getBBForReference(Fn, TyID), - Args); + ResultInst = Builder.createBranch(Loc, getBBForReference(Fn, TyID), Args); break; } case SILInstructionKind::CondBranchInst: { @@ -2161,9 +2152,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I + 1], Fn))); - ResultVal = Builder.createCondBranch(Loc, Cond, - getBBForReference(Fn, ListOfValues[1]), TrueArgs, - getBBForReference(Fn, ListOfValues[2]), FalseArgs); + ResultInst = Builder.createCondBranch( + Loc, Cond, getBBForReference(Fn, ListOfValues[1]), TrueArgs, + getBBForReference(Fn, ListOfValues[2]), FalseArgs); break; } case SILInstructionKind::SwitchEnumInst: @@ -2186,10 +2177,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getBBForReference(Fn, ListOfValues[I+1])} ); } if (OpCode == SILInstructionKind::SwitchEnumInst) - ResultVal = Builder.createSwitchEnum(Loc, Cond, DefaultBB, CaseBBs); + ResultInst = Builder.createSwitchEnum(Loc, Cond, DefaultBB, CaseBBs); else - ResultVal = Builder.createSwitchEnumAddr(Loc, Cond, - DefaultBB, CaseBBs); + ResultInst = Builder.createSwitchEnumAddr(Loc, Cond, DefaultBB, CaseBBs); break; } case SILInstructionKind::SelectEnumInst: @@ -2218,11 +2208,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Value}); } if (OpCode == SILInstructionKind::SelectEnumInst) - ResultVal = Builder.createSelectEnum(Loc, Cond, ResultTy, - DefaultVal, CaseVals); + ResultInst = + Builder.createSelectEnum(Loc, Cond, ResultTy, DefaultVal, CaseVals); else - ResultVal = Builder.createSelectEnumAddr(Loc, Cond, ResultTy, - DefaultVal, CaseVals); + ResultInst = Builder.createSelectEnumAddr(Loc, Cond, ResultTy, DefaultVal, + CaseVals); break; } case SILInstructionKind::SwitchValueInst: { @@ -2245,7 +2235,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto value = getLocalValue(ListOfValues[I], ResultTy); CaseBBs.push_back( {value, getBBForReference(Fn, ListOfValues[I+1])} ); } - ResultVal = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs); + ResultInst = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs); break; } case SILInstructionKind::SelectValueInst: { @@ -2273,8 +2263,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, CaseValuesAndResults.push_back({CaseValue, Result}); } - ResultVal = Builder.createSelectValue(Loc, Cond, ResultTy, - DefaultVal, CaseValuesAndResults); + ResultInst = Builder.createSelectValue(Loc, Cond, ResultTy, DefaultVal, + CaseValuesAndResults); break; } case SILInstructionKind::EnumInst: { @@ -2285,7 +2275,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Operand = getLocalValue(ValID2, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)); - ResultVal = Builder.createEnum( + ResultInst = Builder.createEnum( Loc, Operand, cast(MF->getDecl(ValID)), getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); break; @@ -2297,9 +2287,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, (SILValueCategory) TyCategory, Fn); SILType ResultTy = OperandTy.getEnumElementType( Elt, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createInitEnumDataAddr(Loc, - getLocalValue(ValID2, OperandTy), - Elt, ResultTy); + ResultInst = Builder.createInitEnumDataAddr( + Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case SILInstructionKind::UncheckedEnumDataInst: { @@ -2309,9 +2298,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILType ResultTy = OperandTy.getEnumElementType( Elt, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createUncheckedEnumData(Loc, - getLocalValue(ValID2, OperandTy), - Elt, ResultTy); + ResultInst = Builder.createUncheckedEnumData( + Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case SILInstructionKind::UncheckedTakeEnumDataAddrInst: { @@ -2321,16 +2309,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILType ResultTy = OperandTy.getEnumElementType( Elt, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createUncheckedTakeEnumDataAddr(Loc, - getLocalValue(ValID2, OperandTy), - Elt, ResultTy); + ResultInst = Builder.createUncheckedTakeEnumDataAddr( + Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case SILInstructionKind::InjectEnumAddrInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); - ResultVal = Builder.createInjectEnumAddr( + ResultInst = Builder.createInjectEnumAddr( Loc, getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), Elt); @@ -2344,15 +2331,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(Ty, (SILValueCategory)TyCategory, Fn)); auto ResultTy = Val->getType().getFieldType( Field, SILMod, Builder.getTypeExpansionContext()); - ResultVal = Builder.createRefElementAddr(Loc, Val, Field, - ResultTy, /*Immutable*/ Attr & 0x1); + ResultInst = Builder.createRefElementAddr(Loc, Val, Field, ResultTy, + /*Immutable*/ Attr & 0x1); break; } case SILInstructionKind::RefTailAddrInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); assert((SILValueCategory)TyCategory == SILValueCategory::Address); - ResultVal = Builder.createRefTailAddr( + ResultInst = Builder.createRefTailAddr( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)), @@ -2380,24 +2367,24 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, switch (OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::ClassMethodInst: - ResultVal = Builder.createClassMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createClassMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; case SILInstructionKind::SuperMethodInst: - ResultVal = Builder.createSuperMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createSuperMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; case SILInstructionKind::ObjCMethodInst: - ResultVal = Builder.createObjCMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createObjCMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; case SILInstructionKind::ObjCSuperMethodInst: - ResultVal = Builder.createObjCSuperMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], operandTy), - DRef, Ty); + ResultInst = Builder.createObjCSuperMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); break; } break; @@ -2421,8 +2408,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, if (ValID3) ExistentialOperand = getLocalValue(ValID3, ExistentialOperandTy); } - ResultVal = Builder.createWitnessMethod( - Loc, Ty, Conformance, DRef, OperandTy); + ResultInst = + Builder.createWitnessMethod(Loc, Ty, Conformance, DRef, OperandTy); break; } case SILInstructionKind::DynamicMethodBranchInst: { @@ -2432,7 +2419,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); assert(ListOfValues.size() == NextValueIndex + 2 && "Wrong number of entries for DynamicMethodBranchInst"); - ResultVal = Builder.createDynamicMethodBranch( + ResultInst = Builder.createDynamicMethodBranch( Loc, getLocalValue( ListOfValues[0], @@ -2455,9 +2442,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto *successBB = getBBForReference(Fn, ListOfValues[5]); auto *failureBB = getBBForReference(Fn, ListOfValues[6]); - ResultVal = Builder.createCheckedCastBranch( - Loc, isExact, op, targetLoweredType, targetFormalType, - successBB, failureBB); + ResultInst = + Builder.createCheckedCastBranch(Loc, isExact, op, targetLoweredType, + targetFormalType, successBB, failureBB); break; } case SILInstructionKind::CheckedCastValueBranchInst: { @@ -2472,9 +2459,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto *successBB = getBBForReference(Fn, ListOfValues[5]); auto *failureBB = getBBForReference(Fn, ListOfValues[6]); - ResultVal = Builder.createCheckedCastValueBranch( - Loc, op, srcFormalType, targetLoweredType, targetFormalType, - successBB, failureBB); + ResultInst = Builder.createCheckedCastValueBranch( + Loc, op, srcFormalType, targetLoweredType, targetFormalType, successBB, + failureBB); break; } case SILInstructionKind::UnconditionalCheckedCastValueInst: { @@ -2486,9 +2473,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILType targetLoweredType = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); CanType targetFormalType = MF->getType(ListOfValues[4])->getCanonicalType(); - ResultVal = Builder.createUnconditionalCheckedCastValue(Loc, src, srcFormalType, - targetLoweredType, - targetFormalType); + ResultInst = Builder.createUnconditionalCheckedCastValue( + Loc, src, srcFormalType, targetLoweredType, targetFormalType); break; } case SILInstructionKind::UnconditionalCheckedCastAddrInst: { @@ -2503,8 +2489,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILValue dest = getLocalValue(ListOfValues[5], targetLoweredType); - ResultVal = Builder.createUnconditionalCheckedCastAddr(Loc, src, srcFormalType, - dest, targetFormalType); + ResultInst = Builder.createUnconditionalCheckedCastAddr( + Loc, src, srcFormalType, dest, targetFormalType); break; } case SILInstructionKind::CheckedCastAddrBranchInst: { @@ -2523,10 +2509,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto *successBB = getBBForReference(Fn, ListOfValues[7]); auto *failureBB = getBBForReference(Fn, ListOfValues[8]); - ResultVal = Builder.createCheckedCastAddrBranch(Loc, consumption, - src, srcFormalType, - dest, targetFormalType, - successBB, failureBB); + ResultInst = Builder.createCheckedCastAddrBranch( + Loc, consumption, src, srcFormalType, dest, targetFormalType, successBB, + failureBB); break; } case SILInstructionKind::UncheckedRefCastAddrInst: { @@ -2541,8 +2526,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILValue dest = getLocalValue(ListOfValues[5], destAddrTy); - ResultVal = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, - dest, targetType); + ResultInst = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, dest, + targetType); break; } case SILInstructionKind::InitBlockStorageHeaderInst: { @@ -2563,16 +2548,16 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto SubMap = MF->getSubstitutionMap(ListOfValues[4]); - ResultVal = Builder.createInitBlockStorageHeader(Loc, storage, invoke, - blockTy, SubMap); + ResultInst = Builder.createInitBlockStorageHeader(Loc, storage, invoke, + blockTy, SubMap); break; } case SILInstructionKind::UnreachableInst: { - ResultVal = Builder.createUnreachable(Loc); + ResultInst = Builder.createUnreachable(Loc); break; } case SILInstructionKind::UnwindInst: { - ResultVal = Builder.createUnwind(Loc); + ResultInst = Builder.createUnwind(Loc); break; } case SILInstructionKind::YieldInst: { @@ -2589,7 +2574,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, ListOfValues[I + 2], getSILType(valueTy, valueCategory, Fn))); } - ResultVal = Builder.createYield(Loc, yieldedValues, resumeBB, unwindBB); + ResultInst = Builder.createYield(Loc, yieldedValues, resumeBB, unwindBB); break; } case SILInstructionKind::KeyPathInst: { @@ -2640,8 +2625,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto opCat = (SILValueCategory)ListOfValues[nextValue++]; operands.push_back(getLocalValue(opValue, getSILType(opTy, opCat, Fn))); } - - ResultVal = Builder.createKeyPath(Loc, pattern, subMap, operands, kpTy); + + ResultInst = Builder.createKeyPath(Loc, pattern, subMap, operands, kpTy); break; } case SILInstructionKind::DifferentiableFunctionInst: { @@ -2674,7 +2659,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Optional> derivativeFunctions = None; if (hasDerivativeFunctions) derivativeFunctions = std::make_pair(operands[1], operands[2]); - ResultVal = Builder.createDifferentiableFunction( + ResultInst = Builder.createDifferentiableFunction( Loc, paramIndices, resultIndices, operands[0], derivativeFunctions); break; } @@ -2699,8 +2684,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Optional transposeFunction = None; if (hasLinearFunction) transposeFunction = operands[1]; - ResultVal = Builder.createLinearFunction( - Loc, paramIndices, operands[0], transposeFunction); + ResultInst = Builder.createLinearFunction(Loc, paramIndices, operands[0], + transposeFunction); break; } case SILInstructionKind::DifferentiableFunctionExtractInst: { @@ -2711,7 +2696,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Optional explicitExtracteeType = None; if (Attr2) explicitExtracteeType = silTy; - ResultVal = Builder.createDifferentiableFunctionExtract( + ResultInst = Builder.createDifferentiableFunctionExtract( Loc, extractee, val, explicitExtracteeType); break; } @@ -2720,7 +2705,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto silTy = getSILType(astTy, SILValueCategory::Object, Fn); auto val = getLocalValue(ValID, silTy); LinearDifferentiableFunctionTypeComponent extractee(Attr); - ResultVal = Builder.createLinearFunctionExtract(Loc, extractee, val); + ResultInst = Builder.createLinearFunctionExtract(Loc, extractee, val); break; } case SILInstructionKind::DifferentiabilityWitnessFunctionInst: { @@ -2732,13 +2717,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto astTy = MF->getType(TyID); if (TyID) explicitFnTy = getSILType(astTy, SILValueCategory::Object, Fn); - ResultVal = Builder.createDifferentiabilityWitnessFunction( + ResultInst = Builder.createDifferentiabilityWitnessFunction( Loc, witnessKind, witness, explicitFnTy); break; } } - for (auto result : ResultVal->getResults()) { + for (auto result : ResultInst->getResults()) { LastValueID = LastValueID + 1; setLocalValue(result, LastValueID); } From 44a7038f9e64232fb3639f3454eb9e56c81e5cd3 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Sat, 5 Sep 2020 11:27:54 -0400 Subject: [PATCH 599/663] [benchmark] Address review comments on FP conversion benchmarks --- .../single-source/FloatingPointConversion.swift | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/benchmark/single-source/FloatingPointConversion.swift b/benchmark/single-source/FloatingPointConversion.swift index b416b8742482c..1397418ea7f62 100644 --- a/benchmark/single-source/FloatingPointConversion.swift +++ b/benchmark/single-source/FloatingPointConversion.swift @@ -16,15 +16,18 @@ public let FloatingPointConversion = [ BenchmarkInfo( name: "ConvertFloatingPoint.ConcreteDoubleToDouble", runFunction: run_ConvertFloatingPoint_ConcreteDoubleToDouble, - tags: [.validation, .api]), + tags: [.validation, .api], + setUpFunction: { blackHole(doubles) }), BenchmarkInfo( name: "ConvertFloatingPoint.GenericDoubleToDouble", runFunction: run_ConvertFloatingPoint_GenericDoubleToDouble, - tags: [.validation, .api]), + tags: [.validation, .api], + setUpFunction: { blackHole(doubles) }), BenchmarkInfo( name: "ConvertFloatingPoint.MockFloat64ToDouble", runFunction: run_ConvertFloatingPoint_MockFloat64ToDouble, - tags: [.validation, .api]), + tags: [.validation, .api], + setUpFunction: { blackHole(mockFloat64s) }), ] protocol MockBinaryFloatingPoint: BinaryFloatingPoint { @@ -125,11 +128,6 @@ extension MockBinaryFloatingPoint { mutating func round(_ rule: FloatingPointRoundingRule) { _value.round(rule) } } -struct MockFloat32: MockBinaryFloatingPoint { - var _value: Float - init(_ _value: Float) { self._value = _value } -} - struct MockFloat64: MockBinaryFloatingPoint { var _value: Double init(_ _value: Double) { self._value = _value } From 93d4854c34036d1242b1a2c52deae1b23eeed4cd Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Sat, 5 Sep 2020 13:59:06 -0400 Subject: [PATCH 600/663] [test][IRGen] Maybe Windows needs dso_local. In #33816, we forked the local_extern test omitting the check for the extern function, because it wasn't obvious what the match was. It might actually just be missing the dso_local annotation again for the function. Let's try that. --- test/IRGen/local_extern.swift | 3 +-- test/IRGen/local_extern_windows.swift | 10 ---------- 2 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 test/IRGen/local_extern_windows.swift diff --git a/test/IRGen/local_extern.swift b/test/IRGen/local_extern.swift index f60d8f1dbe9f2..06c9a3d5e94bd 100644 --- a/test/IRGen/local_extern.swift +++ b/test/IRGen/local_extern.swift @@ -1,8 +1,7 @@ -// XFAIL: OS=windows-msvc // RUN: %target-swift-frontend -import-objc-header %S/Inputs/local_extern.h %s -emit-ir | %FileCheck %s // CHECK: @var = external {{(dso_local )?}}global i32 // CHECK: @prior_var = internal global i32 -// CHECK: declare i32 @func +// CHECK: declare {{(dso_local )?}}i32 @func // CHECK: define internal i32 @prior_func print("\(_no_prior_var())") diff --git a/test/IRGen/local_extern_windows.swift b/test/IRGen/local_extern_windows.swift deleted file mode 100644 index 23504a76804f5..0000000000000 --- a/test/IRGen/local_extern_windows.swift +++ /dev/null @@ -1,10 +0,0 @@ -// REQUIRES: OS=windows-msvc -// RUN: %target-swift-frontend -import-objc-header %S/Inputs/local_extern.h %s -emit-ir | %FileCheck %s -// CHECK: @var = external {{(dso_local )?}}global i32 -// CHECK: @prior_var = internal global i32 -// CHECK: define internal i32 @prior_func - -print("\(_no_prior_var())") -print("\(_no_prior_func())") -print("\(_prior_var())") -print("\(_prior_func())") From b1c49514f29eda1898097e79639cd634f0a8780e Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Sun, 6 Sep 2020 15:00:25 -0400 Subject: [PATCH 601/663] [userdocs] Flesh out alternatives/workarounds for protocol type non-conformance --- .../protocol-type-non-conformance.md | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md index 1654367811033..5facd9567abef 100644 --- a/userdocs/diagnostics/protocol-type-non-conformance.md +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -52,10 +52,41 @@ In general, any initializers, static members, and associated types required by a Currently, even if a protocol `P` requires no initializers or static members, the existential type `P` does not conform to `P` (with exceptions below). This restriction allows library authors to add such requirements (initializers or static members) to an existing protocol without breaking their users' source code. +## Exceptions + +The Swift protocol `Error` has no required members and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. + +## Alternatives + Concrete types that _do_ conform to protocols can provide functionality similar to that of existential types. For example, the standard library provides the `AnyHashable` type for `Hashable` values. Manual implementation of such __type erasure__ can require specific knowledge of the semantic requirements for each protocol involved and is beyond the scope of this discussion. -For more on using existential types, see [Protocols as Types](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID275) in _The Swift Programming Language_. +In certain scenarios, you might avoid any need for manual type erasure by reworking generic APIs themselves to use existential types instead: -## Exceptions +```swift +func declareAnimalSpeciesDynamically(_ animal: Animal) { + animal.makeNoise() + print("My species is known as \(type(of: animal).species)") +} + +declareAnimalSpeciesDynamically(animal) +// Prints: +// "Meow" +// "My species is known as Felis catus" +``` + +(Note that there is a distinction between the _static_ type of a value as given by the generic parameter `T` and the _dynamic_ type of a value obtained by invoking `type(of:)`. For example, the static type of `animal` is `Animal`, while its dynamic type is `Cat`. Therefore, the two functions `declareAnimalSpecies(_:)` and `declareAnimalSpeciesDynamically(_:)` are not exact replacements of each other.) + +The same technique might be applicable to members of generic types: + +```swift +// Instead of... +struct Habitat { + var animal: T +} +// ...consider: +struct Habitat { + var animal: Animal +} +``` -The Swift protocol `Error` has no required members and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. \ No newline at end of file +For more on using existential types, see [Protocols as Types](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID275) in _The Swift Programming Language_. From bec3136e1a60f8e24433cb79cd1d6e9295502223 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 4 Sep 2020 22:06:51 -0400 Subject: [PATCH 602/663] Sema: Unqualified lookup either needs a source location or a top-level context --- lib/Sema/TypeCheckConstraints.cpp | 8 ++++++-- lib/Sema/TypeCheckPattern.cpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 32f6087c9fb19..8908b485d8040 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -543,6 +543,9 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // name/module qualifier to access top-level name. lookupOptions |= NameLookupFlags::IncludeOuterResults; + if (Loc.isInvalid()) + DC = DC->getModuleScopeContext(); + auto Lookup = TypeChecker::lookupUnqualified(DC, Name, Loc, lookupOptions); auto &Context = DC->getASTContext(); @@ -2459,8 +2462,9 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, auto lookupOptions = defaultUnqualifiedLookupOptions; lookupOptions |= NameLookupFlags::KnownPrivate; auto matchLookup = - lookupUnqualified(DC, DeclNameRef(Context.Id_MatchOperator), SourceLoc(), - lookupOptions); + lookupUnqualified(DC->getModuleScopeContext(), + DeclNameRef(Context.Id_MatchOperator), + SourceLoc(), lookupOptions); auto &diags = DC->getASTContext().Diags; if (!matchLookup) { diags.diagnose(EP->getLoc(), diag::no_match_operator); diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 1e5c3a571df6f..72d5446207b30 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -122,7 +122,7 @@ lookupUnqualifiedEnumMemberElement(DeclContext *DC, DeclNameRef name, auto lookupOptions = defaultUnqualifiedLookupOptions; lookupOptions |= NameLookupFlags::KnownPrivate; auto lookup = - TypeChecker::lookupUnqualified(DC, name, SourceLoc(), lookupOptions); + TypeChecker::lookupUnqualified(DC, name, UseLoc, lookupOptions); return filterForEnumElement(DC, UseLoc, /*unqualifiedLookup=*/true, lookup); } From 658d4bf813e80b683ca95216606065487cb0b96b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 5 Sep 2020 00:04:04 -0400 Subject: [PATCH 603/663] SourceKit: Refactor walkRelatedDecls() to not use unqualified lookup This function used to perform an unqualified lookup without a source location, to either find top-level members or members of a type. Since this form of unqualified lookup is no longer supported, let's instead explicitly call lookupInModule() or lookupQualified(), depending on whether we're looking inside a type or not. --- .../lib/SwiftLang/SwiftSourceDocInfo.cpp | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp index bd366f9de63de..746c13ea30f9f 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp @@ -20,8 +20,9 @@ #include "swift/AST/ASTDemangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" +#include "swift/AST/LookupKinds.h" +#include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" -#include "swift/AST/NameLookupRequests.h" #include "swift/AST/SwiftNameTranslation.h" #include "swift/AST/GenericSignature.h" #include "swift/Basic/SourceManager.h" @@ -484,40 +485,48 @@ void SwiftLangSupport::printFullyAnnotatedSynthesizedDeclaration( template void walkRelatedDecls(const ValueDecl *VD, const FnTy &Fn) { - llvm::SmallDenseMap NamesSeen; - ++NamesSeen[VD->getName()]; - SmallVector RelatedDecls; - if (isa(VD)) return; // Parameters don't have interesting related declarations. - // FIXME: Extract useful related declarations, overloaded functions, - // if VD is an initializer, we should extract other initializers etc. - // For now we use unqualified lookup to fetch other declarations with the same - // base name. auto &ctx = VD->getASTContext(); - auto descriptor = UnqualifiedLookupDescriptor(DeclNameRef(VD->getBaseName()), - VD->getDeclContext()); - auto lookup = evaluateOrDefault(ctx.evaluator, - UnqualifiedLookupRequest{descriptor}, {}); - for (auto result : lookup) { - ValueDecl *RelatedVD = result.getValueDecl(); - if (RelatedVD->getAttrs().isUnavailable(VD->getASTContext())) + + llvm::SmallDenseMap NamesSeen; + ++NamesSeen[VD->getName()]; + + + auto *DC = VD->getDeclContext(); + bool typeLookup = DC->isTypeContext(); + + SmallVector results; + + if (typeLookup) { + auto type = DC->getDeclaredInterfaceType(); + if (!type->is()) { + DC->lookupQualified(type, DeclNameRef(VD->getBaseName()), + NL_QualifiedDefault, results); + } + } else { + namelookup::lookupInModule(DC->getModuleScopeContext(), + VD->getBaseName(), results, + NLKind::UnqualifiedLookup, + namelookup::ResolutionKind::Overloadable, + DC->getModuleScopeContext()); + } + + SmallVector RelatedDecls; + for (auto result : results) { + if (result->getAttrs().isUnavailable(ctx)) continue; - if (RelatedVD != VD) { - ++NamesSeen[RelatedVD->getName()]; + if (result != VD) { + ++NamesSeen[result->getName()]; RelatedDecls.push_back(result); } } // Now provide the results along with whether the name is duplicate or not. - ValueDecl *OriginalBase = VD->getDeclContext()->getSelfNominalTypeDecl(); - for (auto Related : RelatedDecls) { - ValueDecl *RelatedVD = Related.getValueDecl(); - bool SameBase = Related.getBaseDecl() && Related.getBaseDecl() == OriginalBase; - Fn(RelatedVD, SameBase, NamesSeen[RelatedVD->getName()] > 1); - } + for (auto result : RelatedDecls) + Fn(result, typeLookup, NamesSeen[result->getName()] > 1); } //===----------------------------------------------------------------------===// From 83f49b35f2d513f8e4b1ea5fb21f7aeb83877783 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 5 Sep 2020 00:24:55 -0400 Subject: [PATCH 604/663] AST: Remove old unqualified lookup implementation Now that ASTScope is unconditionally enabled, we can remove the old unqualified lookup implementation. Note that unqualified lookup now either requires a source location, or must start from a module-scope context. All existing usages should now respect this invariant. --- lib/AST/UnqualifiedLookup.cpp | 653 +--------------------------------- 1 file changed, 16 insertions(+), 637 deletions(-) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 3c573aad5a796..0581a70ca5284 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -17,17 +17,11 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" -#include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" -#include "swift/AST/ExistentialLayout.h" #include "swift/AST/ImportCache.h" -#include "swift/AST/Initializer.h" -#include "swift/AST/LazyResolver.h" #include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" #include "swift/AST/NameLookupRequests.h" -#include "swift/AST/ParameterList.h" -#include "swift/AST/SourceFile.h" #include "swift/Basic/Debug.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.h" @@ -42,58 +36,6 @@ using namespace swift; using namespace swift::namelookup; - -namespace { - - /// Determine whether unqualified lookup should look at the members of the - /// given nominal type or extension, vs. only looking at type parameters. - template bool shouldLookupMembers(D *decl, SourceLoc loc) { - // Only look at members of this type (or its inherited types) when - // inside the body or a protocol's top-level 'where' clause. (Why the - // 'where' clause? Because that's where you put constraints on - // inherited associated types.) - - // When we have no source-location information, we have to perform member - // lookup. - if (loc.isInvalid() || decl->getBraces().isInvalid()) - return true; - - SourceManager &SM = decl->getASTContext().SourceMgr; - - // If a code completion happens inside a function body, some lookups may - // happen from the 'loc' that is in a different buffer from the 'decl'. - // In such cases, look for members of the 'decl' because we know 'loc' is - // inside a function body in the 'decl'. - if (SM.hasCodeCompletionBuffer()) { - auto completionBufferID = SM.getCodeCompletionBufferID(); - if (SM.getRangeForBuffer(completionBufferID).contains(loc)) { - auto declBufferID = - decl->getDeclContext()->getParentSourceFile()->getBufferID(); - if (completionBufferID != declBufferID) - return true; - } - } - - // Within the braces, always look for members. - auto braces = decl->getBraces(); - if (braces.Start != braces.End && - SM.rangeContainsTokenLoc(braces, loc)) - return true; - - // Within 'where' clause, we can also look for members. - if (auto *whereClause = decl->getTrailingWhereClause()) { - SourceRange whereClauseRange = whereClause->getSourceRange(); - if (whereClauseRange.isValid() && - SM.rangeContainsTokenLoc(whereClauseRange, loc)) { - return true; - } - } - - // Don't look at the members. - return false; - } -} // end anonymous namespace - namespace { class UnqualifiedLookupFactory { @@ -105,11 +47,6 @@ namespace { using ResultsVector = SmallVector; private: - struct ContextAndResolvedIsCascadingUse { - DeclContext *const DC; - const bool isCascadingUse; - }; - /// Finds lookup results based on the types that self conforms to. /// For instance, self always conforms to a struct, enum or class. /// But in addition, self could conform to any number of protocols. @@ -207,8 +144,6 @@ namespace { #endif public: // for exp debugging - SourceFile const *recordedSF = nullptr; - bool recordedIsCascadingUse = false; unsigned resultsSizeBeforeLocalsPass = ~0; public: @@ -224,17 +159,6 @@ namespace { void performUnqualifiedLookup(); private: - struct ContextAndUnresolvedIsCascadingUse { - DeclContext *whereToLook; - Optional isCascadingUse; - ContextAndResolvedIsCascadingUse resolve(const bool resolution) const { - return ContextAndResolvedIsCascadingUse{ - whereToLook, isCascadingUse.getValueOr(resolution)}; - } - }; - - bool useASTScopesForLookup() const; - void lookUpTopLevelNamesInModuleScopeContext(DeclContext *); void lookInASTScopes(); @@ -247,110 +171,16 @@ namespace { /// to record the dividing line between results from first fruitful scope and /// the result. void recordCompletionOfAScope(); - - template void ifNotDoneYet(Fn fn) { - recordCompletionOfAScope(); - if (!isFirstResultEnough()) - fn(); - } - - template void ifNotDoneYet(Fn1 fn1, Fn2 fn2) { - ifNotDoneYet(fn1); - ifNotDoneYet(fn2); - } - + #pragma mark context-based lookup declarations - - void lookupOperatorInDeclContexts(ContextAndUnresolvedIsCascadingUse); - - /// When performing a lookup, we may come across a capture of 'self'. We - /// will need to remember the DeclContext of the innermost captured self so - /// that it can be used as the base DeclContext if we find a lookup result - /// in the enclosing type. \c capturedSelfContext tracks this. - void lookupNamesIntroducedBy(const ContextAndUnresolvedIsCascadingUse, - DeclContext *capturedSelfContext); - - void finishLookingInContext( - AddGenericParameters addGenericParameters, - DeclContext *lookupContextForThisContext, - Optional &&resultFinderForTypeContext, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupInModuleScopeContext(DeclContext *, Optional isCascadingUse); - - void lookupNamesIntroducedByPatternBindingInitializer( - PatternBindingInitializer *PBI, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void - lookupNamesIntroducedByLazyVariableInitializer(PatternBindingInitializer *PBI, - ParamDecl *selfParam, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByInitializerOfStoredPropertyOfAType( - PatternBindingInitializer *PBI, Optional isCascadingUse); - - /// An initializer of a global name, or a function-likelocal name. - void lookupNamesIntroducedByInitializerOfGlobalOrLocal( - PatternBindingInitializer *PBI, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByFunctionDecl(AbstractFunctionDecl *AFD, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByMemberFunction(AbstractFunctionDecl *AFD, - bool isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByPureFunction(AbstractFunctionDecl *AFD, - bool isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByClosure(AbstractClosureExpr *ACE, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - template - void lookupNamesIntroducedByNominalTypeOrExtension( - NominalTypeDeclOrExtensionDecl *D, Optional isCascadingUse); - - void lookupNamesIntroducedByDefaultArgumentInitializer( - DefaultArgumentInitializer *I, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookupNamesIntroducedByMiscContext(DeclContext *dc, - Optional isCascadingUse, - DeclContext *capturedSelfContext); - - void lookForLocalVariablesIn(AbstractFunctionDecl *AFD, - Optional isCascadingUse); - void lookForLocalVariablesIn(ClosureExpr *); - void lookForLocalVariablesIn(SourceFile *); - + bool isOutsideBodyOfFunction(const AbstractFunctionDecl *const AFD) const; - void addGenericParametersForContext(DeclContext *dc); - void addGenericParametersForContext(GenericParamList *); - - /// Consume generic parameters - void addGenericParametersForFunction(AbstractFunctionDecl *AFD); - - static GenericParamList *getGenericParams(const DeclContext *const dc); - /// For diagnostic purposes, move aside the unavailables, and put /// them back as a last-ditch effort. /// Could be cleaner someday with a richer interface to UnqualifiedLookup. void setAsideUnavailableResults(size_t firstPossiblyUnavailableResult); - void recordDependencyOnTopLevelName(DeclContext *topLevelContext, - DeclNameRef name, bool isCascadingUse); - void addImportedResults(DeclContext *const dc); void addNamesKnownToDebugClient(DeclContext *dc); @@ -369,19 +199,6 @@ namespace { : None; } - static bool resolveIsCascadingUse(const DeclContext *const dc, - Optional isCascadingUse, - bool onlyCareAboutFunctionBody) { - return isCascadingUse.getValueOr(dc->isCascadingContextForLookup( - /*functionsAreNonCascading=*/onlyCareAboutFunctionBody)); - } - - static bool resolveIsCascadingUse(ContextAndUnresolvedIsCascadingUse x, - bool onlyCareAboutFunctionBody) { - return resolveIsCascadingUse(x.whereToLook, x.isCascadingUse, - onlyCareAboutFunctionBody); - } - void findResultsAndSaveUnavailables( DeclContext *lookupContextForThisContext, ResultFinderForTypeContext &&resultFinderForTypeContext, @@ -483,21 +300,24 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { "performUnqualifedLookup", DC->getParentSourceFile()); - const Optional initialIsCascadingUse = getInitialIsCascadingUse(); - - ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUse{ - DC, initialIsCascadingUse}; - if (useASTScopesForLookup()) { + if (Loc.isValid()) { lookInASTScopes(); } else { + assert(DC->isModuleScopeContext() && + "Unqualified lookup without a source location must start from " + "a module-scope context"); + #ifndef NDEBUG stopForDebuggingIfStartingTargetLookup(false); #endif + } - if (Name.isOperator()) - lookupOperatorInDeclContexts(contextAndIsCascadingUse); - else - lookupNamesIntroducedBy(contextAndIsCascadingUse, NULL); + recordCompletionOfAScope(); + if (!isFirstResultEnough()) { + // If no result has been found yet, the dependency must be on a top-level + // name, since up to now, the search has been for non-top-level names. + auto *moduleScopeContext = DC->getModuleScopeContext(); + lookUpTopLevelNamesInModuleScopeContext(moduleScopeContext); } } @@ -522,380 +342,8 @@ void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext( recordCompletionOfAScope(); } -bool UnqualifiedLookupFactory::useASTScopesForLookup() const { - if (!Loc.isValid()) - return false; - return (bool) DC->getParentSourceFile(); -} - #pragma mark context-based lookup definitions -void UnqualifiedLookupFactory::lookupOperatorInDeclContexts( - const ContextAndUnresolvedIsCascadingUse contextAndUseArg) { - ContextAndResolvedIsCascadingUse contextAndResolvedIsCascadingUse{ - // Operators are global - contextAndUseArg.whereToLook->getModuleScopeContext(), - resolveIsCascadingUse(contextAndUseArg, - /*onlyCareAboutFunctionBody*/ true)}; - lookupInModuleScopeContext(contextAndResolvedIsCascadingUse.DC, - contextAndResolvedIsCascadingUse.isCascadingUse); -} - -// TODO: Unify with LookupVisibleDecls.cpp::lookupVisibleDeclsImpl -void UnqualifiedLookupFactory::lookupNamesIntroducedBy( - const ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUseArg, - DeclContext *capturedSelfContext) { -#ifndef NDEBUG - stopForDebuggingIfDuringTargetLookup(false); -#endif - DeclContext *const dc = contextAndIsCascadingUseArg.whereToLook; - const auto isCascadingUseSoFar = contextAndIsCascadingUseArg.isCascadingUse; - if (dc->isModuleScopeContext()) { - assert(capturedSelfContext == NULL && "By the time we reach module scope," - " there should be no 'self'."); - lookupInModuleScopeContext(dc, isCascadingUseSoFar); - } - else if (auto *PBI = dyn_cast(dc)) - lookupNamesIntroducedByPatternBindingInitializer(PBI, isCascadingUseSoFar, - capturedSelfContext); - else if (auto *AFD = dyn_cast(dc)) - lookupNamesIntroducedByFunctionDecl(AFD, isCascadingUseSoFar, - capturedSelfContext); - else if (auto *ACE = dyn_cast(dc)) - lookupNamesIntroducedByClosure(ACE, isCascadingUseSoFar, - capturedSelfContext); - else if (auto *ED = dyn_cast(dc)) { - assert(capturedSelfContext == NULL && "When we recurse into type context," - " 'self' should be forgotten."); - lookupNamesIntroducedByNominalTypeOrExtension(ED, isCascadingUseSoFar); - } - else if (auto *ND = dyn_cast(dc)) { - assert(capturedSelfContext == NULL && "When we recurse into type context," - " 'self' should be forgotten."); - lookupNamesIntroducedByNominalTypeOrExtension(ND, isCascadingUseSoFar); - } - else if (auto I = dyn_cast(dc)) - lookupNamesIntroducedByDefaultArgumentInitializer(I, isCascadingUseSoFar, - capturedSelfContext); - else - lookupNamesIntroducedByMiscContext(dc, isCascadingUseSoFar, - capturedSelfContext); -} - -void UnqualifiedLookupFactory::lookupInModuleScopeContext( - DeclContext *dc, Optional isCascadingUse) { - if (auto SF = dyn_cast(dc)) { - resultsSizeBeforeLocalsPass = Results.size(); - lookForLocalVariablesIn(SF); - } - ifNotDoneYet([&] { - // If no result has been found yet, the dependency must be on a top-level - // name, since up to now, the search has been for non-top-level names. - recordDependencyOnTopLevelName(dc, Name, isCascadingUse.getValueOr(true)); - lookUpTopLevelNamesInModuleScopeContext(dc); - }); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByPatternBindingInitializer( - PatternBindingInitializer *PBI, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // Lazy variable initializer contexts have a 'self' parameter for - // instance member lookup. - if (auto *selfParam = PBI->getImplicitSelfDecl()) - lookupNamesIntroducedByLazyVariableInitializer(PBI, selfParam, - isCascadingUse, - capturedSelfContext); - else if (PBI->getParent()->isTypeContext()) { - assert(capturedSelfContext == NULL && "If we were in a type's property" - " initializer, there should be no 'self' to have been captured."); - lookupNamesIntroducedByInitializerOfStoredPropertyOfAType( - PBI, - isCascadingUse); - } - else - lookupNamesIntroducedByInitializerOfGlobalOrLocal(PBI, isCascadingUse, - capturedSelfContext); -} - - void UnqualifiedLookupFactory::lookupNamesIntroducedByLazyVariableInitializer( - PatternBindingInitializer *PBI, ParamDecl *selfParam, - Optional isCascadingUse, DeclContext *capturedSelfContext) { - Consumer.foundDecl(selfParam, DeclVisibilityKind::FunctionParameter); - ifNotDoneYet([&] { - DeclContext *const patternContainer = PBI->getParent(); - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - patternContainer, - ResultFinderForTypeContext(this, PBI, patternContainer), - resolveIsCascadingUse(PBI, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on - }); -} - -void UnqualifiedLookupFactory:: - lookupNamesIntroducedByInitializerOfStoredPropertyOfAType( - PatternBindingInitializer *PBI, Optional isCascadingUse) { - // Initializers for stored properties of types perform static - // lookup into the surrounding context. - DeclContext *const storedPropertyContainer = PBI->getParent(); - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - storedPropertyContainer, - ResultFinderForTypeContext( - this, storedPropertyContainer, storedPropertyContainer), - resolveIsCascadingUse(storedPropertyContainer, None, - /*onlyCareAboutFunctionBody=*/false), - /*capturedSelfContext=*/NULL); - // clang-format on -} - -void UnqualifiedLookupFactory:: - lookupNamesIntroducedByInitializerOfGlobalOrLocal( - PatternBindingInitializer *PBI, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // There's not much to find here, we'll keep going up to a parent - // context. - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - PBI, - None, // not looking in the partic type - resolveIsCascadingUse(PBI, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByFunctionDecl( - AbstractFunctionDecl *AFD, Optional isCascadingUseArg, - DeclContext *capturedSelfContext) { - - // DOUG: how does this differ from isOutsideBodyOfFunction below? - const bool isCascadingUse = - AFD->isCascadingContextForLookup(false) && - (isCascadingUseArg.getValueOr( - Loc.isInvalid() || AFD->getBodySourceRange().isInvalid() || - !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc))); - - if (AFD->getDeclContext()->isTypeContext()) - lookupNamesIntroducedByMemberFunction(AFD, isCascadingUse, - capturedSelfContext); - else - lookupNamesIntroducedByPureFunction(AFD, isCascadingUse, - capturedSelfContext); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByMemberFunction( - AbstractFunctionDecl *AFD, bool isCascadingUse, - DeclContext *capturedSelfContext) { - lookForLocalVariablesIn(AFD, isCascadingUse); - ifNotDoneYet( - [&] { - // If we're inside a function context, we're about to move to - // the parent DC, so we have to check the function's generic - // parameters first. - // Cannot start here in finishLookingInContext because AFD's - // getOuterParameters may be null even when AFD's parent has generics. - addGenericParametersForFunction(AFD); - }, - [&] { - DeclContext *const fnDeclContext = AFD->getDeclContext(); - // If we're not in the body of the function (for example, we - // might be type checking a default argument expression and - // performing name lookup from there), the base declaration - // is the nominal type, not 'self'. If we've captured self - // somewhere down the tree, we should use that as the context - // for lookup. - DeclContext *const BaseDC = - isOutsideBodyOfFunction(AFD) ? fnDeclContext - : capturedSelfContext ? capturedSelfContext - : AFD; - // If we are inside of a method, check to see if there are any ivars in - // scope, and if so, whether this is a reference to one of them. - // FIXME: We should persist this information between lookups. - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - AFD->getParent(), - ResultFinderForTypeContext(this, BaseDC, fnDeclContext), - isCascadingUse, - NULL); - // clang-format on - }); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByPureFunction( - AbstractFunctionDecl *AFD, bool isCascadingUse, - DeclContext *capturedSelfContext) { - lookForLocalVariablesIn(AFD, isCascadingUse); - ifNotDoneYet([&] { - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - AFD, - None, - isCascadingUse, - capturedSelfContext); - }); -} - - -void UnqualifiedLookupFactory::lookupNamesIntroducedByClosure( - AbstractClosureExpr *ACE, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - if (auto *CE = dyn_cast(ACE)) { - lookForLocalVariablesIn(CE); - // If we don't already have a captured self context, and this closure - // captures the self param (not weakly, so that implicit self is available), - // remember that. - if (capturedSelfContext == nullptr) - if (CE->capturesSelfEnablingImplictSelf()) - capturedSelfContext = CE; - } - ifNotDoneYet([&] { - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - ACE, - None, - resolveIsCascadingUse(ACE, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on - }); -} - -template -void UnqualifiedLookupFactory::lookupNamesIntroducedByNominalTypeOrExtension( - NominalTypeDeclOrExtensionDecl *D, Optional isCascadingUse) { - // clang-format off - finishLookingInContext( - AddGenericParameters::Yes, - D, - shouldLookupMembers(D, Loc) - ? Optional( - ResultFinderForTypeContext(this, D, D)) - : None, - resolveIsCascadingUse(D, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - /*capturedSelfContext=*/NULL); - - // clang-format on -} - -void UnqualifiedLookupFactory:: - lookupNamesIntroducedByDefaultArgumentInitializer( - DefaultArgumentInitializer *I, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // In a default argument, skip immediately out of both the - // initializer and the function. - finishLookingInContext(AddGenericParameters::No, I->getParent(), None, false, - capturedSelfContext); -} - -void UnqualifiedLookupFactory::lookupNamesIntroducedByMiscContext( - DeclContext *dc, Optional isCascadingUse, - DeclContext *capturedSelfContext) { - // clang-format off - assert(isa(dc) || - isa(dc) || - isa(dc) || - isa(dc) || - isa(dc)); - finishLookingInContext( - AddGenericParameters::Yes, - dc, - None, - resolveIsCascadingUse(DC, isCascadingUse, - /*onlyCareAboutFunctionBody=*/false), - capturedSelfContext); - // clang-format on -} - - -void UnqualifiedLookupFactory::finishLookingInContext( - const AddGenericParameters addGenericParameters, - DeclContext *const lookupContextForThisContext, - Optional &&resultFinderForTypeContext, - const Optional isCascadingUse, - DeclContext *capturedSelfContext) { -#ifndef NDEBUG - stopForDebuggingIfDuringTargetLookup(false); -#endif - // When a generic has the same name as a member, Swift prioritizes the generic - // because the member could still be named by qualifying it. But there is no - // corresponding way to qualify a generic parameter. - // So, look for generics first. - if (addGenericParameters == AddGenericParameters::Yes) - addGenericParametersForContext(lookupContextForThisContext); - - ifNotDoneYet( - [&] { - if (resultFinderForTypeContext) - findResultsAndSaveUnavailables(lookupContextForThisContext, - std::move(*resultFinderForTypeContext), - *isCascadingUse, baseNLOptions); - }, - // Recurse into the next context. - [&] { - lookupNamesIntroducedBy(ContextAndUnresolvedIsCascadingUse{ - lookupContextForThisContext->getParentForLookup(), isCascadingUse}, - capturedSelfContext); - }); -} - - -void UnqualifiedLookupFactory::lookForLocalVariablesIn( - AbstractFunctionDecl *AFD, Optional isCascadingUse) { - // Look for local variables; normally, the parser resolves these - // for us, but it can't do the right thing inside local types. - // FIXME: when we can parse and typecheck the function body partially - // for code completion, AFD->getBody() check can be removed. - - if (Loc.isInvalid() || AFD->getBodySourceRange().isInvalid() || - !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc) || - !AFD->getBody()) { - return; - } - - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.visit(AFD->getBody()); - - ifNotDoneYet([&] { - if (auto *P = AFD->getImplicitSelfDecl()) - localVal.checkValueDecl(P, DeclVisibilityKind::FunctionParameter); - localVal.checkParameterList(AFD->getParameters()); - }); -} - -void UnqualifiedLookupFactory::lookForLocalVariablesIn(ClosureExpr *CE) { - // Look for local variables; normally, the parser resolves these - // for us, but it can't do the right thing inside local types. - if (Loc.isInvalid()) - return; - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - if (auto body = CE->getBody()) - localVal.visit(body); - ifNotDoneYet([&] { - if (auto params = CE->getParameters()) - localVal.checkParameterList(params); - }); -} - -void UnqualifiedLookupFactory::lookForLocalVariablesIn(SourceFile *SF) { - if (Loc.isInvalid()) - return; - // Look for local variables in top-level code; normally, the parser - // resolves these for us, but it can't do the right thing for - // local types. - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkSourceFile(*SF); -} - bool UnqualifiedLookupFactory::isOutsideBodyOfFunction( const AbstractFunctionDecl *const AFD) const { return !AFD->isImplicit() && Loc.isValid() && @@ -903,48 +351,6 @@ bool UnqualifiedLookupFactory::isOutsideBodyOfFunction( !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc); } -GenericParamList * -UnqualifiedLookupFactory::getGenericParams(const DeclContext *const dc) { - if (auto nominal = dyn_cast(dc)) - return nominal->getGenericParams(); - if (auto ext = dyn_cast(dc)) - return ext->getGenericParams(); - if (auto subscript = dyn_cast(dc)) - return subscript->getGenericParams(); - if (auto func = dyn_cast(dc)) - return func->getGenericParams(); - return nullptr; -} - -void UnqualifiedLookupFactory::addGenericParametersForContext( - DeclContext *dc) { - // Generics can be nested, so visit the generic list, innermost first. - // Cannot use DeclContext::forEachGenericContext because this code breaks out - // if it finds a match and isFirstResultEnough() - addGenericParametersForContext(getGenericParams(dc)); -} - -void UnqualifiedLookupFactory::addGenericParametersForContext( - GenericParamList *dcGenericParams) { - if (!dcGenericParams) - return; - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkGenericParams(dcGenericParams); - ifNotDoneYet([&] { - addGenericParametersForContext( - dcGenericParams->getOuterParameters()); - }); -} - -void UnqualifiedLookupFactory::addGenericParametersForFunction( - AbstractFunctionDecl *AFD) { - GenericParamList *GenericParams = AFD->getGenericParams(); - if (GenericParams) { - namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkGenericParams(GenericParams); - } -} - void UnqualifiedLookupFactory::ResultFinderForTypeContext::findResults( const DeclNameRef &Name, bool isCascadingUse, NLOptions baseNLOptions, DeclContext *contextForLookup, @@ -998,13 +404,6 @@ void UnqualifiedLookupFactory::setAsideUnavailableResults( filterForDiscriminator(Results, DebugClient); } - -void UnqualifiedLookupFactory::recordDependencyOnTopLevelName( - DeclContext *topLevelContext, DeclNameRef name, bool isCascadingUse) { - recordedSF = dyn_cast(topLevelContext); - recordedIsCascadingUse = isCascadingUse; -} - void UnqualifiedLookupFactory::addImportedResults(DeclContext *const dc) { using namespace namelookup; SmallVector CurModuleResults; @@ -1144,28 +543,8 @@ void UnqualifiedLookupFactory::lookInASTScopes() { stopForDebuggingIfStartingTargetLookup(true); #endif - const auto history = ASTScope::unqualifiedLookup(DC->getParentSourceFile(), - Name, Loc, DC, consumer); - - ifNotDoneYet([&] { - // Copied from lookupInModuleScopeContext - // If no result has been found yet, the dependency must be on a top-level - // name, since up to now, the search has been for non-top-level names. - auto *const moduleScopeContext = DC->getParentSourceFile(); - - const Optional isCascadingUseAtStartOfLookup = - !Name.isOperator() - ? getInitialIsCascadingUse() - : resolveIsCascadingUse(DC, getInitialIsCascadingUse(), - /*onlyCareAboutFunctionBody*/ true); - - const Optional isCascadingUseAfterLookup = - ASTScope::computeIsCascadingUse(history, isCascadingUseAtStartOfLookup); - - recordDependencyOnTopLevelName(moduleScopeContext, Name, - isCascadingUseAfterLookup.getValueOr(true)); - lookUpTopLevelNamesInModuleScopeContext(moduleScopeContext); - }); + ASTScope::unqualifiedLookup(DC->getParentSourceFile(), + Name, Loc, DC, consumer); } bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( From 14aaa2eb41ead3a756240e7e99f164a06db692d2 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:27:51 -0400 Subject: [PATCH 605/663] [docs] Minor revision of trailing closure matching edu note --- .../diagnostics/trailing-closure-matching.md | 98 ++++++++++--------- 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/userdocs/diagnostics/trailing-closure-matching.md b/userdocs/diagnostics/trailing-closure-matching.md index d373191f27839..2221bf621535a 100644 --- a/userdocs/diagnostics/trailing-closure-matching.md +++ b/userdocs/diagnostics/trailing-closure-matching.md @@ -1,102 +1,110 @@ # Argument Matching for Trailing Closures -In Swift, calling a function with one or more trailing closure arguments requires the label of the first trailing closure argument to be omitted. As a result, the compiler must consider additional context when determining which function parameter the trailing closure should satisfy. - -Before Swift 5.3, the compiler used a backward scanning rule to match a trailing closure to a function parameter. Starting from the end of the parameter list, it moved backwards until finding a parameter which could accept a trailing closure argument (a function type, unconstrained generic parameter, `Any`, etc.). This could sometimes lead to unexpected behavior. Consider the following example: +Where trailing closures are used to pass one or more arguments to a function, the argument label for the first trailing closure is always omitted: ```swift func animate( withDuration duration: Double, animations: () -> Void, completion: (() -> Void)? = nil -) {} +) { /* ... */ } -// OK -animate(withDuration: 0.3, animations: { /* Animate Something */ }) { - // Done! +animate(withDuration: 0.3) /* `animate:` is unwritten. */ { + // Animate something. +} completion: { + // Completion handler. } +``` -// error: missing argument for parameter 'animations' in call +Sometimes, an unlabeled trailing closure argument can be matched to more than one function parameter. Before Swift 5.3, the compiler would use a __backward scanning rule__ to match the unlabeled trailing closure, scanning backwards from the end of the parameter list until the first parameter that can accept a closure argument (a function type, unconstrained generic type, `Any`, etc.): + +```swift animate(withDuration: 0.3) { - // Animate Something + // Animate something? + // The compiler matches this to the `completion` parameter. } +// error: missing argument for parameter 'animations' in call ``` -The second call to `animate` results in a compiler error because the backward scanning rule matches the trailing closure to the `completion` parameter instead of `animations`. +We encounter a compiler error in this example because the backward scanning rule matches the trailing closure to the `completion` parameter instead of the `animations` parameter, even though `completion` has a default value while `animations` does not. -Beginning in Swift 5.3, the compiler uses a new, forward scanning rule to match trailing closures to function parameters. When matching function arguments to parameters, the forward scan first matches all non-trailing arguments from left-to-right. Then, it continues matching trailing closures in a left-to-right manner. This leads to more predictable and easy-to-understand behavior in many situations. With the new rule, the example above now works as expected without any modifications: +Swift 5.3 introduces a new __forward scanning rule__, which matches trailing closures to function parameters from left to right. This leads to more predictable and easy-to-understand behavior in many situations. With the new rule, the unlabeled closure in the example above is matched to the `animations` parameter, just as most users would expect: ```swift -// Remains valid -animate(withDuration: 0.3, animations: { /* Animate Something */ }) { - // Done! -} - -// Also OK! animate(withDuration: 0.3) { - // Animate Something -} + // Animate something. +} // `completion` has the default value `nil`. ``` -When scanning forwards to match an unlabeled trailing closure argument, the compiler may sometimes need to "skip over" defaulted and variadic arguments. The new rule will skip any parameter that does not structurally resemble a function type. This allows writing a modified version of the above example where `withDuration` also has a default argument value: +When scanning forwards to match an unlabeled trailing closure argument, the compiler will skip any parameter that does not __structurally resemble__ a function type and also apply a __heuristic__ to skip parameters that do not require an argument in favor of a subsequent parameter that does (see below). These rules make possible the ergonomic use of a modified version of the API given in the example above, where `withDuration` has a default value: ```swift func animate( withDuration duration: Double = 1.0, animations: () -> Void, completion: (() -> Void)? = nil -) {} +) { /* ... */ } -// Allowed! The forward scanning rule skips `withDuration` because it does not -// structurally resemble a function type. animate { - // Animate Something + // Animate something. + // + // The closure is not matched to `withDuration` but to `animations` because + // the first parameter doesn't structurally resemble a function type. + // + // If, in place of `withDuration`, there is a parameter with a default value + // that does structurally resemble a function type, the closure would still be + // matched to `animations` because it requires an argument while the first + // parameter does not. } ``` +For source compatibility in Swift 5, the compiler will attempt to apply *both* the new forward scanning rule and the old backward scanning rule when it encounters a function call with a single trailing closure. If the forward and backward scans produce *different valid* matches of arguments to parameters, the compiler will prefer the result of the backward scanning rule and produce a warning. To silence this warning, rewrite the function call to label the argument explicitly without using trailing closure syntax. + +## Structural Resemblance to a Function Type + A parameter structurally resembles a function type if both of the following are true: -- The parameter is not `inout` -- The adjusted type of the parameter is a function type +- the parameter is not `inout`, and +- the __adjusted type__ of the parameter is a function type. The adjusted type of the parameter is the parameter's type as it appears in the function declaration, looking through any type aliases, and performing three additional adjustments: -- If the parameter is an `@autoclosure`, using the result type of the parameter's declared (function) type, before performing the second adjustment. -- If the parameter is variadic, looking at the base element type. -- Removing all outer "optional" types. +1. If the parameter is an `@autoclosure`, use the result type of the parameter's declared (function) type before performing the second adjustment. +2. If the parameter is variadic, look at the base element type. +3. Remove all outer "optional" types. + +## Heuristic for Skipping Parameters -To maintain source compatibility with code that was written before Swift 5.3, the forward scanning rule applies an additional heuristic when matching trailing closure arguments. If, +To maintain source compatibility, the forward scanning rule applies an additional heuristic when matching trailing closure arguments. If: - the parameter that would match an unlabeled trailing closure argument according to the forward scanning rule does not require an argument (because it is variadic or has a default argument), _and_ -- there are parameters _following_ that parameter that _do_ require an argument, which appear before the first parameter whose label matches that of the _next_ trailing closure (if any) +- there are parameters _following_ that parameter that _do_ require an argument, which appear before the first parameter whose label matches that of the _next_ trailing closure (if any), -then the compiler does not match the unlabeled trailing closure to that parameter. Instead, it skips it and examines the next parameter to see if that should be matched against the unlabeled trailing closure. This can be seen in the following example: +then the compiler does not match the unlabeled trailing closure to that parameter. Instead, it examines the next parameter to see if that should be matched to the unlabeled trailing closure, as in the following example: ```swift func showAlert( message: String, onPresentation: (() -> Void)? = nil, onDismissal: () -> Void -) {} +) { /* ... */ } -// The unlabeled trailing closure matches `onDismissal` because `onPresentation` -// does not require an argument, but `onDismissal` does and there are no other -// trailing closures which could match it. +// `onPresentation` does not require an argument, but `onDismissal` does, and +// there is no subsequent trailing closure labeled `onDismissal`. +// Therefore, the unlabeled trailing closure is matched to `onDismissal`. showAlert(message: "Hello, World!") { - // On dismissal action + // On dismissal action. } -// The unlabeled trailing closure matches `onPresentation` because although -// `onPresentation` does not require an argument, there are no parameters -// following it which require an argument and appear before the parameter -// whose label matches the next trailing closure argument (`onDismissal`). +// Although `onPresentation` does not require an argument, there are no +// subsequent parameters that require an argument before the parameter whose +// label matches the next trailing closure (`onDismissal`). +// Therefore, the unlabeled trailing closure is matched to `onPresentation`. showAlert(message: "Hello, World!") { - // On presentation action + // On presentation action. } onDismissal: { - // On dismissal action + // On dismissal action. } ``` -Additionally, the Swift 5 compiler will attempt to apply both the new forward scanning rule and the old backward scanning rule when it encounters a call with a single trailing closure. If the forward and backward scans produce *different* valid assignments of arguments to parameters, the compiler will prefer the result of the backward scanning rule and produce a warning. - To learn more about argument matching for trailing closures, see [Swift Evolution Proposal SE-0286](https://github.com/apple/swift-evolution/blob/master/proposals/0286-forward-scan-trailing-closures.md). From 680682fc539b72a7c7e2d8c1897f9710bc861006 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:51:51 -0400 Subject: [PATCH 606/663] [docs] Update educational note for accuracy about `Error` requirements --- userdocs/diagnostics/protocol-type-non-conformance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md index 5facd9567abef..d3dbadfdf6eb6 100644 --- a/userdocs/diagnostics/protocol-type-non-conformance.md +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -54,7 +54,7 @@ Currently, even if a protocol `P` requires no initializers or static members, th ## Exceptions -The Swift protocol `Error` has no required members and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. +When used as a type, the Swift protocol `Error` conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves. ## Alternatives From 369275169015e429dbec3c475f0beca9c4372388 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Mon, 7 Sep 2020 01:23:00 +0100 Subject: [PATCH 607/663] [Benchmark] Fix build failure on armv7 by guarding Float80 availability --- benchmark/single-source/FloatingPointConversion.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/benchmark/single-source/FloatingPointConversion.swift b/benchmark/single-source/FloatingPointConversion.swift index 1397418ea7f62..ebf2c6d4b19a3 100644 --- a/benchmark/single-source/FloatingPointConversion.swift +++ b/benchmark/single-source/FloatingPointConversion.swift @@ -61,7 +61,9 @@ extension MockBinaryFloatingPoint { init(_ value: Int) { self.init(_Value(value)) } init(_ value: Float) { self.init(_Value(value)) } init(_ value: Double) { self.init(_Value(value)) } - init(_ value: Float80) { self.init(_Value(value)) } + #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + init(_ value: Float80) { self.init(_Value(value)) } + #endif init(integerLiteral value: _Value.IntegerLiteralType) { self.init(_Value(integerLiteral: value)) } From 4103cb8a35b43606074b85c3065479e3ee3f17d9 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Sun, 6 Sep 2020 20:30:02 -0400 Subject: [PATCH 608/663] [docs] Restore original wording in two places about trailing closure matching --- userdocs/diagnostics/trailing-closure-matching.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/userdocs/diagnostics/trailing-closure-matching.md b/userdocs/diagnostics/trailing-closure-matching.md index 2221bf621535a..25f743b3432a3 100644 --- a/userdocs/diagnostics/trailing-closure-matching.md +++ b/userdocs/diagnostics/trailing-closure-matching.md @@ -16,7 +16,7 @@ animate(withDuration: 0.3) /* `animate:` is unwritten. */ { } ``` -Sometimes, an unlabeled trailing closure argument can be matched to more than one function parameter. Before Swift 5.3, the compiler would use a __backward scanning rule__ to match the unlabeled trailing closure, scanning backwards from the end of the parameter list until the first parameter that can accept a closure argument (a function type, unconstrained generic type, `Any`, etc.): +Sometimes, an unlabeled trailing closure argument can be matched to more than one function parameter. Before Swift 5.3, the compiler would use a __backward scanning rule__ to match the unlabeled trailing closure, scanning backwards from the end of the parameter list until finding a parameter that can accept a closure argument (a function type, unconstrained generic type, `Any`, etc.): ```swift animate(withDuration: 0.3) { @@ -28,7 +28,7 @@ animate(withDuration: 0.3) { We encounter a compiler error in this example because the backward scanning rule matches the trailing closure to the `completion` parameter instead of the `animations` parameter, even though `completion` has a default value while `animations` does not. -Swift 5.3 introduces a new __forward scanning rule__, which matches trailing closures to function parameters from left to right. This leads to more predictable and easy-to-understand behavior in many situations. With the new rule, the unlabeled closure in the example above is matched to the `animations` parameter, just as most users would expect: +Swift 5.3 introduces a new __forward scanning rule__, which matches trailing closures to function parameters from left to right (after matching non-trailing arguments). This leads to more predictable and easy-to-understand behavior in many situations. With the new rule, the unlabeled closure in the example above is matched to the `animations` parameter, just as most users would expect: ```swift animate(withDuration: 0.3) { From 97dde3d114fe128d80544a4e91446f76dab4d059 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 7 Sep 2020 08:40:34 +0100 Subject: [PATCH 609/663] Remove unused MutexWASI.cpp --- stdlib/public/runtime/CMakeLists.txt | 1 - stdlib/public/runtime/MutexWASI.cpp | 25 ------------------------- 2 files changed, 26 deletions(-) delete mode 100644 stdlib/public/runtime/MutexWASI.cpp diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index cceac025b9f16..c8e874a01e717 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -58,7 +58,6 @@ set(swift_runtime_sources MetadataLookup.cpp MutexPThread.cpp MutexWin32.cpp - MutexWASI.cpp Numeric.cpp Once.cpp Portability.cpp diff --git a/stdlib/public/runtime/MutexWASI.cpp b/stdlib/public/runtime/MutexWASI.cpp deleted file mode 100644 index e62f54c107483..0000000000000 --- a/stdlib/public/runtime/MutexWASI.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===--- MutexWin32.cpp - -------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// Mutex, ConditionVariable, Read/Write lock, and Scoped lock implementations -// using Windows Slim Reader/Writer Locks and Conditional Variables. -// -//===----------------------------------------------------------------------===// - -#if defined(__wasi__) -#include "swift/Runtime/Mutex.h" - -using namespace swift; - -void ConditionPlatformHelper::wait(ConditionHandle &condition, - MutexHandle &mutex) {} -#endif From df0117e9cb3942202f4a4ba4b9503136d707db18 Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Mon, 7 Sep 2020 07:08:06 -0400 Subject: [PATCH 610/663] [docs] Address typo in trailing closure education note --- userdocs/diagnostics/trailing-closure-matching.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/userdocs/diagnostics/trailing-closure-matching.md b/userdocs/diagnostics/trailing-closure-matching.md index 25f743b3432a3..f1ce7c0fdf939 100644 --- a/userdocs/diagnostics/trailing-closure-matching.md +++ b/userdocs/diagnostics/trailing-closure-matching.md @@ -9,7 +9,7 @@ func animate( completion: (() -> Void)? = nil ) { /* ... */ } -animate(withDuration: 0.3) /* `animate:` is unwritten. */ { +animate(withDuration: 0.3) /* `animations:` is unwritten. */ { // Animate something. } completion: { // Completion handler. From 3c5322d50d5c0893ed07210a8343759cd48f1c0b Mon Sep 17 00:00:00 2001 From: YR Chen Date: Mon, 7 Sep 2020 20:30:30 +0800 Subject: [PATCH 611/663] [docs] Deprecate Python 2 in Windows build instructions (#33819) --- docs/WindowsBuild.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 4260e19a78172..039b1fdcaca5d 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -8,11 +8,10 @@ The commands below (with the exception of installing Visual Studio) must be ente ### Visual Studio -An easy way to get most of the tools to build Swift is using the [Visual Studio installer](https://www.visualstudio.com/downloads/). This command installs all needed Visual Studio components as well as Python and Git: +An easy way to get most of the tools to build Swift is using the [Visual Studio installer](https://www.visualstudio.com/downloads/). This command installs all needed Visual Studio components as well as Python, Git, CMake and Ninja: ``` vs_community ^ - --add Component.CPython2.x86 ^ --add Component.CPython3.x64 ^ --add Microsoft.VisualStudio.Component.Git ^ --add Microsoft.VisualStudio.Component.VC.ATL ^ @@ -28,13 +27,7 @@ The following [link](https://docs.microsoft.com/visualstudio/install/workload-co ### Python -The command above already installs Python 2 and 3. Alternatively, in the Visual Studio installation program, under *Individual Components* - -1. Install *Python 2*, either the 32-bit version (C:\Python27\\) or the 64-bit version (C:\Python27amd64\\) - - **Note:** If you install the 64-bit version only, you will need to adjust `PYTHON_EXECUTABLE` below to `C:\Python27amd64\python.exe` - -2. Install *Python 3 64 bits (3.7.x)* +The command above already installs Python 3. Alternatively, in the Visual Studio installation program, under *Individual Components*, install *Python 3 64 bits (3.7.x)*. If you are building a debug version of Swift, you should also install the Python debug binaries. @@ -137,9 +130,6 @@ cmake -B "S:\b\toolchain" ^ ninja -C S:\b\toolchain ``` -**Note:** If you installed only the 64-bit version of Python, you will need to adjust `PYTHON_EXECUTABLE` argument to `C:\Python27amd64\python.exe` - - ## Running Swift tests on Windows ```cmd @@ -176,7 +166,7 @@ path S:\b\foundation\Foundation;%PATH% ## Build swift-corelibs-xctest ```cmd -cmake -B S:\b\xctest -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D dispatch_DIR=S:\b\dispatch\cmake\modules -D Foundation_DIR=S:\b\foundation\cmake\modules -D LIT_COMMAND=S:\toolchain\llvm\utils\lit\lit.py -D PYTHON_EXECUTABLE=C:\Python27\python.exe -G Ninja -S S:\swift-corelibs-xctest +cmake -B S:\b\xctest -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D dispatch_DIR=S:\b\dispatch\cmake\modules -D Foundation_DIR=S:\b\foundation\cmake\modules -D LIT_COMMAND=S:\toolchain\llvm\utils\lit\lit.py -G Ninja -S S:\swift-corelibs-xctest ninja -C S:\b\xctest ``` From f8d8005ce61dca06c1b368fde40e7e883a55e625 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 7 Sep 2020 09:21:16 -0400 Subject: [PATCH 612/663] [Changelog] Add entries for SE-0279 and SE-0286 (#33729) --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc73f1d979750..fb765f84639a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,35 @@ Swift Next Swift 5.3 --------- +* [SE-0279][] & [SE-0286][]: + + Trailing closure syntax has been extended to allow additional labeled closures to follow the initial unlabeled closure: + + ```swift + // Single trailing closure argument + UIView.animate(withDuration: 0.3) { + self.view.alpha = 0 + } + // Multiple trailing closure arguments + UIView.animate(withDuration: 0.3) { + self.view.alpha = 0 + } completion: { _ in + self.view.removeFromSuperview() + } + ``` + + Additionally, trailing closure arguments now match the appropriate parameter according to a forward-scan rule (as opposed to the previous backward-scan rule): + + ```swift + func takesClosures(first: () -> Void, second: (Int) -> Void = { _ in }) {} + + takesClosures { + print("First") + } + ``` + + In the above example, the trailing closure argument matches parameter `first`, whereas pre-Swift-5.3 it would have matched `second`. In order to ease the transition to this new rule, cases in which the forward-scan and backward-scan match a single trailing closure to different parameters, the backward-scan result is preferred and a warning is emitted. This is expected to be upgraded to an error in the next major version of Swift. + * [SR-7083][]: Property observers such as `willSet` and `didSet` are now supported on `lazy` properties: @@ -8112,7 +8141,9 @@ Swift 1.0 [SE-0268]: [SE-0269]: [SE-0276]: +[SE-0279]: [SE-0280]: +[SE-0286]: [SE-0287]: [SR-75]: From edf89476426039b50300acff25aafd052eee9f14 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 7 Sep 2020 09:46:29 -0700 Subject: [PATCH 613/663] Update WindowsBuild.md - Sort the arguments to CMake to make them easier to spot - Sort the clones to be in order of use - Use shorter build directory names as the paths can be troublesome - Update instructions all the way through to swift-package-manager as that now works - Fix instructions for cloning swift-llbuild (the repository contains symlinks) - Add instructions for new swift-package-manager dependencies - Homogenise the build rules (they are at this point, largely copy-paste from each one, just listing dependencies) - Switch `swift-llbuild` to use `clang-cl` instead of `cl` and add a workaround for code splitting --- docs/WindowsBuild.md | 217 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 183 insertions(+), 34 deletions(-) diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 039b1fdcaca5d..603fb16cfc843 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -62,9 +62,13 @@ git clone https://github.com/apple/swift-cmark cmark git clone https://github.com/apple/swift-corelibs-libdispatch swift-corelibs-libdispatch git clone https://github.com/apple/swift-corelibs-foundation swift-corelibs-foundation git clone https://github.com/apple/swift-corelibs-xctest swift-corelibs-xctest -git clone https://github.com/apple/swift-llbuild llbuild git clone https://github.com/apple/swift-tools-support-core swift-tools-support-core -git clone -c core.autocrlf=input https://github.com/apple/swift-package-manager swiftpm +git clone -c core.symlinks=true https://github.com/apple/swift-llbuild swift-llbuild +git clone https://github.com/JPSim/Yams Yams +git clone https://github.com/apple/swift-driver swift-driver +git clone https://github.com/apple/swift-argument-parser swift-argument-parser +git clone -c core.autocrlf=input https://github.com/apple/swift-package-manager swift-package-manager +git clone https://github.com/apple/indexstore-db indexstore-db ``` ## Dependencies (ICU, SQLite3, curl, libxml2 and zlib) @@ -112,116 +116,261 @@ Warning: Creating the above links usually requires administrator privileges. The ## Build the toolchain ```cmd -cmake -B "S:\b\toolchain" ^ +cmake -B "S:\b\1" ^ -C S:\swift\cmake\caches\Windows-x86_64.cmake ^ -D CMAKE_BUILD_TYPE=Release ^ - -D SWIFT_PATH_TO_LIBDISPATCH_SOURCE=S:\swift-corelibs-libdispatch ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D LLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-windows-msvc ^ -D LLVM_ENABLE_PDB=YES ^ - -D LLVM_EXTERNAL_SWIFT_SOURCE_DIR=S:\swift ^ -D LLVM_EXTERNAL_CMARK_SOURCE_DIR=S:\cmark ^ - -D SWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE=S:\Library\icu-67\usr\include ^ - -D SWIFT_WINDOWS_x86_64_ICU_UC=S:\Library\icu-67\usr\lib\icuuc67.lib ^ + -D LLVM_EXTERNAL_SWIFT_SOURCE_DIR=S:\swift ^ + -D SWIFT_PATH_TO_LIBDISPATCH_SOURCE=S:\swift-corelibs-libdispatch ^ -D SWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE=S:\Library\icu-67\usr\include ^ -D SWIFT_WINDOWS_x86_64_ICU_I18N=S:\Library\icu-67\usr\lib\icuin67.lib ^ - -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D SWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE=S:\Library\icu-67\usr\include ^ + -D SWIFT_WINDOWS_x86_64_ICU_UC=S:\Library\icu-67\usr\lib\icuuc67.lib ^ -G Ninja ^ -S S:\llvm-project\llvm -ninja -C S:\b\toolchain +ninja -C S:\b\1 ``` ## Running Swift tests on Windows ```cmd -path S:\Library\icu-67\usr\bin;S:\b\toolchain\bin;S:\b\toolchain\tools\swift\libdispatch-prefix\bin;%PATH%;%ProgramFiles%\Git\usr\bin +path S:\Library\icu-67\usr\bin;S:\b\1\bin;S:\b\1\tools\swift\libdispatch-prefix\bin;%PATH%;%ProgramFiles%\Git\usr\bin ninja -C S:\b\toolchain check-swift ``` ## Build swift-corelibs-libdispatch ```cmd -cmake -B S:\b\libdispatch -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_CXX_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D ENABLE_SWIFT=YES -G Ninja -S S:\swift-corelibs-libdispatch -ninja -C S:\b\libdispatch +cmake -B S:\b\2 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_CXX_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D ENABLE_SWIFT=YES ^ + -G Ninja ^ + -S S:\swift-corelibs-libdispatch + +ninja -C S:\b\2 ``` ## Test swift-corelibs-libdispatch ```cmd -ninja -C S:\b\libdispatch check +ninja -C S:\b\2 check ``` ## Build swift-corelibs-foundation ```cmd -cmake -B S:\b\foundation -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" -D ICU_ROOT="S:/Library/icu-67" -D ICU_INCLUDE_DIR=S:/Library/icu-67/usr/include -D LIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2s.lib" -D LIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include/libxml2" -D ENABLE_TESTING=NO -D dispatch_DIR=S:/b/libdispatch/cmake/modules -G Ninja -S S:\swift-corelibs-foundation -ninja -C S:\b\foundation +cmake -B S:\b\3 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" ^ + -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" ^ + -D ICU_I18N_LIBRARY_RELEASE=S:\library\icu-67\usr\lib\icuin67.lib ^ + -D ICU_ROOT=S:\Library\icu-67\usr ^ + -D ICU_UC_LIBRARY_RELEASE=S:\Library\icu-67\usr\lib\icuuc67.lib ^ + -D LIBXML2_LIBRARY=S:\Library\libxml2-development\usr\lib\libxml2s.lib ^ + -D LIBXML2_INCLUDE_DIR=S:\Library\libxml2-development\usr\include\libxml2 ^ + -D ENABLE_TESTING=NO ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -G Ninja ^ + -S S:\swift-corelibs-foundation + +ninja -C S:\b\3 ``` - Add Foundation to your path: ```cmd -path S:\b\foundation\Foundation;%PATH% +path S:\b\3\bin;%PATH% ``` ## Build swift-corelibs-xctest ```cmd -cmake -B S:\b\xctest -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D dispatch_DIR=S:\b\dispatch\cmake\modules -D Foundation_DIR=S:\b\foundation\cmake\modules -D LIT_COMMAND=S:\toolchain\llvm\utils\lit\lit.py -G Ninja -S S:\swift-corelibs-xctest -ninja -C S:\b\xctest +cmake -B S:\b\4 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D LIT_COMMAND=S:\llvm-project\llvm\utils\lit\lit.py ^ + -G Ninja ^ + -S S:\swift-corelibs-xctest + +ninja -C S:\b\4 ``` - Add XCTest to your path: ```cmd -path S:\b\xctest;%PATH% + +path S:\b\4;%PATH% ``` ## Test XCTest ```cmd -ninja -C S:\b\xctest check-xctest +ninja -C S:\b\4 check-xctest ``` ## Rebuild Foundation ```cmd -cmake -B S:\b\foundation -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" -D ICU_ROOT="S:/Library/icu-67" -D LIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2.lib" -D LIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include" -D ENABLE_TESTING=YES -D dispatch_DIR=S:/b/libdispatch/cmake/modules -D XCTest_DIR=S:/b/xctest/cmake/modules -G Ninja -S S:\swift-corelibs-foundation -ninja -C S:\b\foundation +cmake -B S:\b\3 ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" ^ + -D CURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" ^ + -D ICU_I18N_LIBRARY_RELEASE=S:\library\icu-67\usr\lib\icuin67.lib ^ + -D ICU_ROOT=S:\Library\icu-67\usr ^ + -D ICU_UC_LIBRARY_RELEASE=S:\Library\icu-67\usr\lib\icuuc67.lib ^ + -D LIBXML2_LIBRARY=S:\Library\libxml2-development\usr\lib\libxml2s.lib ^ + -D LIBXML2_INCLUDE_DIR=S:\Library\libxml2-development\usr\include\libxml2 ^ + -D ENABLE_TESTING=YES ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D XCTest_DIR=S:\b\4\cmake\modules ^ + -G Ninja ^ + -S S:\swift-corelibs-foundation + +ninja -C S:\b\3 ``` ## Test Foundation ```cmd -cmake --build S:\b\foundation -ninja -C S:\b\foundation test +ninja -C S:\b\3 test ``` -## Build llbuild +## Build swift-tools-core-support ```cmd -set AR=llvm-ar -cmake -B S:\b\llbuild -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_CXX_COMPILER=cl -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D Foundation_DIR=S:/b/foundation/cmake/modules -D dispatch_DIR=S:/b/libdispatch/cmake/modules -D SQLite3_INCLUDE_DIR=S:\Library\sqlite-3.28.0\usr\include -D SQLite3_LIBRARY=S:\Library\sqlite-3.28.0\usr\lib\sqlite3.lib -D LLBUILD_SUPPORT_BINDINGS=Swift -G Ninja -S S:\llbuild -ninja -C S:\b\llbuild +cmake -B S:\b\5 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D SQLite3_INCLUDE_DIR=S:\Library\sqlite-3.28.0\usr\include ^ + -D SQLite3_LIBRARY=S:\Library\sqlite-3.28.0\usr\lib\SQLite3.lib ^ + -G Ninja ^ + -S S:\swift-tools-support-core + +ninja -C S:\b\5 +``` + +## Build swift-llbuild + +```cmd +cmake -B S:\b\6 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=RelWithDebInfo ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_CXX_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CMAKE_CXX_FLAGS="-Xclang -fno-split-cold-code" ^ + -D LLBUILD_SUPPORT_BINDINGS=Swift ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D SQLite3_INCLUDE_DIR=S:\Library\sqlite-3.28.0\usr\include ^ + -D SQLite3_LIBRARY=S:\Library\sqlite-3.28.0\usr\lib\sqlite3.lib ^ + -G Ninja ^ + -S S:\swift-llbuild + +ninja -C S:\b\6 ``` - Add llbuild to your path: ```cmd -path S:\b\llbuild\bin;%PATH% +path S:\b\6\bin;%PATH% ``` -## Build swift-tools-core-support +## Build Yams ```cmd -cmake -B S:\b\tsc -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=cl -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D Foundation_DIR=S:/b/foundation/cmake/modules -D dispatch_DIR=S:/b/libdispatch/cmake/modules -G Ninja -S S:\swift-tools-support-core -ninja -C S:\b\tsc +cmake -B S:\b\7 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D XCTest_DIR=S:\b\4\cmake\modules ^ + -G Ninja ^ + -S S:\swift-llbuild + +ninja -C S:\b\7 +``` + +## Build swift-driver + +```cmd +cmake -B S:\b\8 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D TSC_DIR=S:\b\5\cmake\modules ^ + -D LLBuild_DIR=S:\b\6\cmake\modules ^ + -D Yams_DIR=S:\b\7\cmake\modules ^ + -G Ninja ^ + -S S:\swift-driver + +ninja -C S:\b\8 +``` + +## Build swift-argument-parser + +```cmd +cmake -B S:\b\9 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D XCTest_DIR=S:\b\4\cmake\modules ^ + -G Ninja ^ + -S S:\swift-argument-parser + +ninja -C S:\b\9 ``` ## Build swift-package-manager ```cmd -cmake -B S:\b\spm -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_C_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_CXX_COMPILER=S:/b/toolchain/bin/clang-cl.exe -D CMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -D USE_VENDORED_TSC=YES -D Foundation_DIR=S:/b/foundation/cmake/modules -D dispatch_DIR=S:/b/libdispatch/cmake/modules -D LLBuild_DIR=S:/b/llbuild/cmake/modules -G Ninja -S S:\swiftpm -ninja -C S:\b\spm +cmake -B S:\b\10 ^ + -D BUILD_SHARED_LIBS=YES ^ + -D CMAKE_BUILD_TYPE=Release ^ + -D CMAKE_C_COMPILER=S:/b/1/bin/clang-cl.exe ^ + -D CMAKE_Swift_COMPILER=S:/b/1/bin/swiftc.exe ^ + -D CMAKE_INSTALL_PREFIX=C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr ^ + -D dispatch_DIR=S:\b\2\cmake\modules ^ + -D Foundation_DIR=S:\b\3\cmake\modules ^ + -D TSC_DIR=S:\b\5\cmake\modules ^ + -D LLBuild_DIR=S:\b\6\cmake\modules ^ + -D Yams_DIR=S:\b\7\cmake\modules ^ + -D SwiftDriver_DIR=S:\b\8\cmake\modules ^ + -D ArgumentParser_DIR=S:\b\9\cmake\modules ^ + -G Ninja ^ + -S S:\swift-package-manager + +ninja -C S:\b\10 ``` ## Install the Swift toolchain on Windows From 79a2ab0c8c921b8cd33c52c9fbebb3f99feb0bbc Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 7 Sep 2020 11:24:39 -0700 Subject: [PATCH 614/663] [ConstraintSystem] Record `unable to infer base` only if hole originated from affected reference If base type of a unresolved member reference couldn't be determined (represented as a hole type), before recording a fix about lack of contextual information, let's make sure that hole originated in either base or result type of this reference, otherwise the problem is contextual e.g. generic parameter, which supposed to act as contextual type for a reference, couldn't be inferred. --- lib/Sema/CSSimplify.cpp | 94 ++++++++++++++----- .../valid_pointer_conversions.swift | 1 - test/decl/enum/enumtest.swift | 3 +- 3 files changed, 69 insertions(+), 29 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 86ae993fb893d..afb594bc871eb 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6966,6 +6966,24 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( auto locator = getConstraintLocator(locatorB); + auto formUnsolved = [&](bool activate = false) { + // If requested, generate a constraint. + if (flags.contains(TMF_GenerateConstraints)) { + auto *memberRef = Constraint::createMemberOrOuterDisjunction( + *this, kind, baseTy, memberTy, member, useDC, functionRefKind, + outerAlternatives, locator); + + addUnsolvedConstraint(memberRef); + + if (activate) + activateConstraint(memberRef); + + return SolutionKind::Solved; + } + + return SolutionKind::Unsolved; + }; + // If the base type of this member lookup is a "hole" there is no // reason to perform a lookup because it wouldn't return any results. if (shouldAttemptFixes()) { @@ -6977,15 +6995,57 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( // If this is an unresolved member ref e.g. `.foo` and its contextual base // type has been determined to be a "hole", let's mark the resulting member // type as a potential hole and continue solving. - if (kind == ConstraintKind::UnresolvedValueMember && - baseObjTy->getMetatypeInstanceType()->isHole()) { - auto *fix = - SpecifyBaseTypeForContextualMember::create(*this, member, locator); - if (recordFix(fix)) - return SolutionKind::Error; + if (kind == ConstraintKind::UnresolvedValueMember) { + // Let's look through all metatypes to find "underlying" type + // of this lookup. + Type underlyingType = baseObjTy; + while (auto *MT = underlyingType->getAs()) { + underlyingType = MT->getInstanceType(); + } + + // Let's delay solving this constraint in diagnostic + // mode until it's certain that there is no way to + // find out what the base type is. + if (underlyingType->isTypeVariableOrMember()) + return formUnsolved(); - markMemberTypeAsPotentialHole(memberTy); - return SolutionKind::Solved; + // Let's record a fix only if the hole originates either + // at the result of the chain (that could happen since solving + // of this constraint is delayed until base could be resolved), + // or it is certain that base type can't be bound to any other + // type but a hole. + auto shouldRecordFixForHole = [&](HoleType *baseType) { + auto *originator = + baseType->getOriginatorType().dyn_cast(); + + if (!originator) + return false; + + auto *originatorLoc = originator->getImpl().getLocator(); + + // It could either be a hole associated directly with the base + // or a hole which came from result type of the chain. + if (originatorLoc->isLastElement< + LocatorPathElt::UnresolvedMemberChainResult>()) { + auto *UMCR = castToExpr( + originatorLoc->getAnchor()); + return UMCR->getChainBase() == getAsExpr(locator->getAnchor()); + } + + return originatorLoc == locator; + }; + + if (auto *hole = underlyingType->getAs()) { + if (shouldRecordFixForHole(hole)) { + auto *fix = SpecifyBaseTypeForContextualMember::create(*this, member, + locator); + if (recordFix(fix)) + return SolutionKind::Error; + } + + markMemberTypeAsPotentialHole(memberTy); + return SolutionKind::Solved; + } } else if ((kind == ConstraintKind::ValueMember || kind == ConstraintKind::ValueWitness) && baseObjTy->getMetatypeInstanceType()->isHole()) { @@ -7000,24 +7060,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( performMemberLookup(kind, member, baseTy, functionRefKind, locator, /*includeInaccessibleMembers*/ shouldAttemptFixes()); - auto formUnsolved = [&](bool activate = false) { - // If requested, generate a constraint. - if (flags.contains(TMF_GenerateConstraints)) { - auto *memberRef = Constraint::createMemberOrOuterDisjunction( - *this, kind, baseTy, memberTy, member, useDC, functionRefKind, - outerAlternatives, locator); - - addUnsolvedConstraint(memberRef); - - if (activate) - activateConstraint(memberRef); - - return SolutionKind::Solved; - } - - return SolutionKind::Unsolved; - }; - switch (result.OverallResult) { case MemberLookupResult::Unsolved: return formUnsolved(); diff --git a/test/Constraints/valid_pointer_conversions.swift b/test/Constraints/valid_pointer_conversions.swift index 1cb1fb4ff1887..265083a6bc211 100644 --- a/test/Constraints/valid_pointer_conversions.swift +++ b/test/Constraints/valid_pointer_conversions.swift @@ -45,5 +45,4 @@ SR12382(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePoint //problem/68254165 - Bad diagnostic when using String init(decodingCString:) with an incorrect pointer type func rdar68254165(ptr: UnsafeMutablePointer) { _ = String(decodingCString: ptr, as: .utf8) // expected-error {{generic parameter 'Encoding' could not be inferred}} - // expected-error@-1 {{type '_.Type' has no member 'utf8'}} } diff --git a/test/decl/enum/enumtest.swift b/test/decl/enum/enumtest.swift index 57b8117e65b0c..3f5a450adf228 100644 --- a/test/decl/enum/enumtest.swift +++ b/test/decl/enum/enumtest.swift @@ -100,8 +100,7 @@ func test3a(_ a: ZeroOneTwoThree) { var h = ZeroOneTwoThree(1) var i = 0 > 3 ? .none : .some(3) // expected-error {{cannot infer contextual base in reference to member 'none'}} - // expected-error@-1 {{cannot infer contextual base in reference to member 'some'}} - + test3a; // expected-error {{unused function}} .Zero // expected-error {{reference to member 'Zero' cannot be resolved without a contextual type}} test3a // expected-error {{unused function}} From 4b3d15d65a2767900c6f2cb8e5615a759353134e Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 7 Sep 2020 14:24:49 -0700 Subject: [PATCH 615/663] Update WindowsBuild.md Add some documentation on how swift-package-manager finds the package description before installation. --- docs/WindowsBuild.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 603fb16cfc843..b66f30f0516cc 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -373,6 +373,11 @@ cmake -B S:\b\10 ^ ninja -C S:\b\10 ``` +Indicate to swift-package-manager where to find the Package Description before installation: +```cmd +set SWIFTPM_PD_LIBS=S:\b\10\pm +``` + ## Install the Swift toolchain on Windows - Run ninja install: From 4f464ff0d4efdf77ff67dc6dd2966840ed5236a1 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 7 Sep 2020 19:09:54 -0700 Subject: [PATCH 616/663] [Localization] Extract testing fixture and diagnostic definitions into a header Doing so make it easy to share common bits of localization testing infrastructure. --- .../Localization/DefToYAMLConverterTests.cpp | 69 +------------- unittests/Localization/LocalizationTest.h | 94 +++++++++++++++++++ 2 files changed, 99 insertions(+), 64 deletions(-) create mode 100644 unittests/Localization/LocalizationTest.h diff --git a/unittests/Localization/DefToYAMLConverterTests.cpp b/unittests/Localization/DefToYAMLConverterTests.cpp index 19ad8cef98b4e..0c10c2463131d 100644 --- a/unittests/Localization/DefToYAMLConverterTests.cpp +++ b/unittests/Localization/DefToYAMLConverterTests.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "LocalizationTest.h" #include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" @@ -19,8 +20,6 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/YAMLParser.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" #include @@ -30,22 +29,7 @@ using namespace swift; using namespace swift::diag; - -enum LocalDiagID : uint32_t { -#define DIAG(KIND, ID, Options, Text, Signature) ID, -#include "swift/AST/DiagnosticsAll.def" - NumDiags -}; - -static constexpr const char *const diagnosticID[] = { -#define DIAG(KIND, ID, Options, Text, Signature) #ID, -#include "swift/AST/DiagnosticsAll.def" -}; - -static constexpr const char *const diagnosticMessages[] = { -#define DIAG(KIND, ID, Options, Text, Signature) Text, -#include "swift/AST/DiagnosticsAll.def" -}; +using namespace swift::unittests; static std::string getMainExecutablePath() { llvm::StringRef libPath = llvm::sys::path::parent_path(SWIFTLIB_DIR); @@ -62,50 +46,7 @@ static std::string getDefaultLocalizationPath() { return std::string(DefaultDiagnosticMessagesDir); } -struct DefToYAMLConverterTest : public ::testing::Test { - std::string YAMLPath; - -public: - DefToYAMLConverterTest() { - llvm::SmallString<128> tempFilename; - std::error_code error = - llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); - assert(!error); - - YAMLPath = std::string(tempFilename); - } - - void SetUp() override { - bool failed = convertDefIntoYAML(YAMLPath); - assert(!failed && "failed to generate a YAML file"); - } - - void TearDown() override { llvm::sys::fs::remove(YAMLPath); } - - /// Random number in [0,n) - unsigned RandNumber(unsigned n) { return unsigned(rand()) % n; } - -protected: - static bool convertDefIntoYAML(std::string outputPath) { - std::error_code error; - llvm::raw_fd_ostream OS(outputPath, error, llvm::sys::fs::F_None); - if (OS.has_error() || error) - return true; - - llvm::ArrayRef ids(diagnosticID, LocalDiagID::NumDiags); - llvm::ArrayRef messages(diagnosticMessages, - LocalDiagID::NumDiags); - - DefToYAMLConverter converter(ids, messages); - converter.convert(OS); - - OS.flush(); - - return OS.has_error(); - } -}; - -TEST_F(DefToYAMLConverterTest, MissingLocalizationFiles) { +TEST_F(LocalizationTest, MissingLocalizationFiles) { ASSERT_TRUE(llvm::sys::fs::exists(getDefaultLocalizationPath())); llvm::SmallString<128> EnglishLocalization(getDefaultLocalizationPath()); llvm::sys::path::append(EnglishLocalization, "en"); @@ -115,7 +56,7 @@ TEST_F(DefToYAMLConverterTest, MissingLocalizationFiles) { ASSERT_TRUE(llvm::sys::fs::exists(EnglishLocalization)); } -TEST_F(DefToYAMLConverterTest, MatchDiagnosticMessagesSequentially) { +TEST_F(LocalizationTest, ConverterTestMatchDiagnosticMessagesSequentially) { YAMLLocalizationProducer yaml(YAMLPath); yaml.forEachAvailable([](swift::DiagID id, llvm::StringRef translation) { llvm::StringRef msg = diagnosticMessages[static_cast(id)]; @@ -123,7 +64,7 @@ TEST_F(DefToYAMLConverterTest, MatchDiagnosticMessagesSequentially) { }); } -TEST_F(DefToYAMLConverterTest, MatchDiagnosticMessagesRandomly) { +TEST_F(LocalizationTest, ConverterTestMatchDiagnosticMessagesRandomly) { YAMLLocalizationProducer yaml(YAMLPath); std::random_device rd; diff --git a/unittests/Localization/LocalizationTest.h b/unittests/Localization/LocalizationTest.h new file mode 100644 index 0000000000000..75586703eeb70 --- /dev/null +++ b/unittests/Localization/LocalizationTest.h @@ -0,0 +1,94 @@ +//===--- LocalizationTest.h - Helper for setting up locale tests -*- C++-*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef LOCALIZATION_TEST_H +#define LOCALIZATION_TEST_H + +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace swift::diag; + +namespace swift { +namespace unittests { + +enum LocalDiagID : uint32_t { +#define DIAG(KIND, ID, Options, Text, Signature) ID, +#include "swift/AST/DiagnosticsAll.def" + NumDiags +}; + +static constexpr const char *const diagnosticID[] = { +#define DIAG(KIND, ID, Options, Text, Signature) #ID, +#include "swift/AST/DiagnosticsAll.def" +}; + +static constexpr const char *const diagnosticMessages[] = { +#define DIAG(KIND, ID, Options, Text, Signature) Text, +#include "swift/AST/DiagnosticsAll.def" +}; + +struct LocalizationTest : public ::testing::Test { + std::string YAMLPath; + + LocalizationTest() { + llvm::SmallString<128> tempFilename; + std::error_code error = + llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); + assert(!error); + + YAMLPath = std::string(tempFilename); + } + + void SetUp() override { + bool failed = convertDefIntoYAML(YAMLPath); + assert(!failed && "failed to generate a YAML file"); + } + + void TearDown() override { llvm::sys::fs::remove(YAMLPath); } + + /// Random number in [0,n) + unsigned RandNumber(unsigned n) { return unsigned(rand()) % n; } + +protected: + static bool convertDefIntoYAML(std::string outputPath) { + std::error_code error; + llvm::raw_fd_ostream OS(outputPath, error, llvm::sys::fs::F_None); + if (OS.has_error() || error) + return true; + + llvm::ArrayRef ids(diagnosticID, LocalDiagID::NumDiags); + llvm::ArrayRef messages(diagnosticMessages, + LocalDiagID::NumDiags); + + DefToYAMLConverter converter(ids, messages); + converter.convert(OS); + + OS.flush(); + + return OS.has_error(); + } +}; + +} // end namespace unittests +} // end namespace swift + +#endif From 0ec6eb2568e46a60e2e2b76e850b3cbb5348a025 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 7 Sep 2020 17:53:20 +0200 Subject: [PATCH 617/663] SimplifyCFG: Handle checked_cast_addr_br with consumption kind copy_on_success We didn't optimize such casts with copy_on_success, which could result in very stupid code, e.g. for type identity casts (which should be a no-op). --- lib/SILOptimizer/Utils/CastOptimizer.cpp | 23 ++++--- .../floating_point_conversion.swift | 25 ++++++++ test/SILOptimizer/simplify_cfg.sil | 64 +++++++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 test/SILOptimizer/floating_point_conversion.swift diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index c1c5da4bc3fdc..3a15d568afc0a 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -918,25 +918,32 @@ SILInstruction *CastOptimizer::simplifyCheckedCastAddrBranchInst( return nullptr; } - // For CopyOnSuccess casts, we could insert an explicit copy here, but this - // case does not happen in practice. - // // Both TakeOnSuccess and TakeAlways can be reduced to an // UnconditionalCheckedCast, since the failure path is irrelevant. + AllocStackInst *copiedSrc = nullptr; switch (Inst->getConsumptionKind()) { case CastConsumptionKind::BorrowAlways: llvm_unreachable("checked_cast_addr_br never has BorrowAlways"); case CastConsumptionKind::CopyOnSuccess: - return nullptr; + if (!Src->getType().isTrivial(*BB->getParent())) { + copiedSrc = Builder.createAllocStack(Loc, Src->getType()); + Builder.createCopyAddr(Loc, Src, copiedSrc, IsNotTake, IsInitialization); + Src = copiedSrc; + } + break; case CastConsumptionKind::TakeAlways: case CastConsumptionKind::TakeOnSuccess: break; } - if (!emitSuccessfulIndirectUnconditionalCast(Builder, Loc, dynamicCast)) { - // No optimization was possible. - return nullptr; - } + bool result = emitSuccessfulIndirectUnconditionalCast( + Builder, Builder.getModule().getSwiftModule(), Loc, Src, + Inst->getSourceFormalType(), Dest, Inst->getTargetFormalType(), Inst); + (void)result; + assert(result && "emit cannot fail for an checked_cast_addr_br"); + + if (copiedSrc) + Builder.createDeallocStack(Loc, copiedSrc); eraseInstAction(Inst); } SILInstruction *NewI = &BB->back(); diff --git a/test/SILOptimizer/floating_point_conversion.swift b/test/SILOptimizer/floating_point_conversion.swift new file mode 100644 index 0000000000000..fb3c84fdc05b0 --- /dev/null +++ b/test/SILOptimizer/floating_point_conversion.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-frontend -O -module-name=test -emit-sil %s | %FileCheck %s + +func convert< + T: BinaryFloatingPoint, U: BinaryFloatingPoint + >(_ value: T, to: U.Type) -> U { + U(value) +} + +// Check that the follwing functions can be optimized to no-ops. + +// CHECK-LABEL: sil @$s4test0A6DoubleyS2dF +// CHECK: return %0 +// CHECK: } // end sil function '$s4test0A6DoubleyS2dF' +public func testDouble(_ x: Double) -> Double { + return convert(x, to: Double.self) +} + +// CHECK-LABEL: sil @$s4test0A5FloatyS2fF +// CHECK: return %0 +// CHECK: } // end sil function '$s4test0A5FloatyS2fF' +public func testFloat(_ x: Float) -> Float { + return convert(x, to: Float.self) +} + + diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil index 6adb3f9859dbc..d19fb986fa0aa 100644 --- a/test/SILOptimizer/simplify_cfg.sil +++ b/test/SILOptimizer/simplify_cfg.sil @@ -2980,6 +2980,70 @@ bb3: br bb2(%z : $Builtin.Int1) } +// CHECK-LABEL: sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int +// CHECK: [[SRC:%.*]] = alloc_stack $Int +// CHECK: store %0 to [[SRC]] +// CHECK: [[DST:%.*]] = alloc_stack $Int +// CHECK: [[LD1:%.*]] = load [[SRC]] +// CHECK: store [[LD1]] to [[DST]] +// CHECK: [[LD2:%.*]] = load [[DST]] +// CHECK: return [[LD2]] +// CHECK: } // end sil function 'trivial_checked_cast_addr_br' +sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int { +bb0(%0 : $Int, %1 : $Int): + %6 = alloc_stack $Int + store %0 to %6 : $*Int + %8 = alloc_stack $Int + checked_cast_addr_br copy_on_success Int in %6 : $*Int to Int in %8 : $*Int, bb1, bb2 + +bb1: + %10 = load %8 : $*Int + dealloc_stack %8 : $*Int + br bb3(%10 : $Int) + +bb2: + retain_value %1: $Int + dealloc_stack %8 : $*Int + br bb3(%1 : $Int) + +bb3(%11 : $Int): + dealloc_stack %6 : $*Int + return %11 : $Int +} + +// CHECK-LABEL: sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String +// CHECK: [[SRC:%.*]] = alloc_stack $String +// CHECK: store %0 to [[SRC]] +// CHECK: [[DST:%.*]] = alloc_stack $String +// CHECK: [[TEMP:%.*]] = alloc_stack $String +// CHECK: copy_addr [[SRC]] to [initialization] [[TEMP]] +// CHECK: [[LD1:%.*]] = load [[TEMP]] +// CHECK: store [[LD1]] to [[DST]] +// CHECK: [[LD2:%.*]] = load [[DST]] +// CHECK: return [[LD2]] +// CHECK: } // end sil function 'non_trivial_checked_cast_addr_br' +sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String { +bb0(%0 : $String, %1 : $String): + %6 = alloc_stack $String + store %0 to %6 : $*String + %8 = alloc_stack $String + checked_cast_addr_br copy_on_success String in %6 : $*String to String in %8 : $*String, bb1, bb2 + +bb1: + %10 = load %8 : $*String + dealloc_stack %8 : $*String + br bb3(%10 : $String) + +bb2: + retain_value %1: $String + dealloc_stack %8 : $*String + br bb3(%1 : $String) + +bb3(%11 : $String): + dealloc_stack %6 : $*String + return %11 : $String +} + // CHECK-LABEL: sil @dont_hang // CHECK: bb6: // CHECK: integer_literal $Builtin.Int64, 1 From 0baf84431e11bbe299c9766d0b4090d4b24f2188 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 8 Sep 2020 01:00:31 -0700 Subject: [PATCH 618/663] [Localization] Expose a way to create temporary files through `LocalizationTest` --- .../Localization/DefToYAMLConverterTests.cpp | 1 - unittests/Localization/LocalizationTest.h | 18 +++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/unittests/Localization/DefToYAMLConverterTests.cpp b/unittests/Localization/DefToYAMLConverterTests.cpp index 0c10c2463131d..1683537cdb05b 100644 --- a/unittests/Localization/DefToYAMLConverterTests.cpp +++ b/unittests/Localization/DefToYAMLConverterTests.cpp @@ -18,7 +18,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" diff --git a/unittests/Localization/LocalizationTest.h b/unittests/Localization/LocalizationTest.h index 75586703eeb70..865f998088cb3 100644 --- a/unittests/Localization/LocalizationTest.h +++ b/unittests/Localization/LocalizationTest.h @@ -19,6 +19,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" #include @@ -50,12 +51,7 @@ struct LocalizationTest : public ::testing::Test { std::string YAMLPath; LocalizationTest() { - llvm::SmallString<128> tempFilename; - std::error_code error = - llvm::sys::fs::createTemporaryFile("en", "yaml", tempFilename); - assert(!error); - - YAMLPath = std::string(tempFilename); + YAMLPath = std::string(createTemporaryFile("en", "yaml")); } void SetUp() override { @@ -63,7 +59,15 @@ struct LocalizationTest : public ::testing::Test { assert(!failed && "failed to generate a YAML file"); } - void TearDown() override { llvm::sys::fs::remove(YAMLPath); } + static std::string createTemporaryFile(std::string prefix, + std::string suffix) { + llvm::SmallString<128> tempFile; + std::error_code error = + llvm::sys::fs::createTemporaryFile(prefix, suffix, tempFile); + assert(!error); + llvm::sys::RemoveFileOnSignal(tempFile); + return std::string(tempFile); + } /// Random number in [0,n) unsigned RandNumber(unsigned n) { return unsigned(rand()) % n; } From dbe79956f4050954f4188fa7529eaebd0954e6ea Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 8 Sep 2020 01:01:50 -0700 Subject: [PATCH 619/663] [Localization] Add localization serialization tests 1. YAML <-> DB format + verification 2. Empty DB to write/read and fallback verification 3. Random holes in the DB file test write/read and fallback --- unittests/Localization/CMakeLists.txt | 3 +- unittests/Localization/SerializationTests.cpp | 113 ++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 unittests/Localization/SerializationTests.cpp diff --git a/unittests/Localization/CMakeLists.txt b/unittests/Localization/CMakeLists.txt index e43fe72f0d451..618d892709403 100644 --- a/unittests/Localization/CMakeLists.txt +++ b/unittests/Localization/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_unittest(swiftLocalizationTests - DefToYAMLConverterTests.cpp) + DefToYAMLConverterTests.cpp + SerializationTests.cpp) target_link_libraries(swiftLocalizationTests PRIVATE diff --git a/unittests/Localization/SerializationTests.cpp b/unittests/Localization/SerializationTests.cpp new file mode 100644 index 0000000000000..5eea041977759 --- /dev/null +++ b/unittests/Localization/SerializationTests.cpp @@ -0,0 +1,113 @@ +//===--- LocalizationProducerTests.cpp -------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "LocalizationTest.h" +#include "swift/Localization/LocalizationFormat.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +#include +#include + +using namespace swift::diag; +using namespace swift::unittests; + +TEST_F(LocalizationTest, TestYAMLSerialization) { + YAMLLocalizationProducer yaml(YAMLPath); + + auto dbFile = createTemporaryFile("en", "db"); + + // First, let's serialize English translations + { + SerializedLocalizationWriter writer; + + yaml.forEachAvailable([&writer](swift::DiagID id, llvm::StringRef translation) { + writer.insert(id, translation); + }); + + ASSERT_FALSE(writer.emit(dbFile)); + } + + // Now, let's make sure that serialized version matches "source" YAML + auto dbContent = llvm::MemoryBuffer::getFile(dbFile); + ASSERT_TRUE(dbContent); + + SerializedLocalizationProducer db(std::move(dbContent.get())); + yaml.forEachAvailable([&db](swift::DiagID id, llvm::StringRef translation) { + ASSERT_EQ(translation, db.getMessageOr(id, "")); + }); +} + +TEST_F(LocalizationTest, TestSerializationOfEmptyFile) { + auto dbFile = createTemporaryFile("by", "db"); + SerializedLocalizationWriter writer; + ASSERT_FALSE(writer.emit(dbFile)); + + YAMLLocalizationProducer yaml(YAMLPath); + + // Reading of the empty `db` file should always return default message. + { + auto dbContent = llvm::MemoryBuffer::getFile(dbFile); + ASSERT_TRUE(dbContent); + + SerializedLocalizationProducer db(std::move(dbContent.get())); + yaml.forEachAvailable([&db](swift::DiagID id, llvm::StringRef translation) { + ASSERT_EQ("<<>>", + db.getMessageOr(id, "<<>>")); + }); + } +} + +TEST_F(LocalizationTest, TestSerializationWithGaps) { + // Initially all of the messages are included. + llvm::SmallBitVector includedMessages(LocalDiagID::NumDiags, true); + + // Let's punch some holes in the diagnostic content. + for (unsigned i = 0, n = 200; i != n; ++i) { + unsigned position = RandNumber(LocalDiagID::NumDiags); + includedMessages.flip(position); + } + + YAMLLocalizationProducer yaml(YAMLPath); + auto dbFile = createTemporaryFile("en", "db"); + + { + SerializedLocalizationWriter writer; + + yaml.forEachAvailable([&](swift::DiagID id, llvm::StringRef translation) { + if (includedMessages.test((unsigned)id)) + writer.insert(id, translation); + }); + + ASSERT_FALSE(writer.emit(dbFile)); + } + + + { + auto dbContent = llvm::MemoryBuffer::getFile(dbFile); + ASSERT_TRUE(dbContent); + + SerializedLocalizationProducer db(std::move(dbContent.get())); + yaml.forEachAvailable([&](swift::DiagID id, llvm::StringRef translation) { + auto position = (unsigned)id; + + std::string expectedMessage = includedMessages.test(position) + ? std::string(translation) + : "<<>>"; + + ASSERT_EQ(expectedMessage, db.getMessageOr(id, "<<>>")); + }); + } +} From db6e3af0023a3e7fdb15204ba95e3a63a53f6deb Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Tue, 8 Sep 2020 17:32:07 +0100 Subject: [PATCH 620/663] [IDE] Fix a typo (#33841) --- lib/IDE/CodeCompletion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index e1785d3598ed3..d0955f257b6dd 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -6072,7 +6072,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { // TypeName at attribute position after '@'. // - VarDecl: Property Wrappers. - // - ParamDecl/VarDecl/FuncDecl: Function Buildres. + // - ParamDecl/VarDecl/FuncDecl: Function Builders. if (!AttTargetDK || *AttTargetDK == DeclKind::Var || *AttTargetDK == DeclKind::Param || *AttTargetDK == DeclKind::Func) Lookup.getTypeCompletionsInDeclContext( From 7f169103dac6370504b4fa8259c7f5bc48d8690f Mon Sep 17 00:00:00 2001 From: Xiaodi Wu <13952+xwu@users.noreply.github.com> Date: Tue, 8 Sep 2020 12:40:33 -0400 Subject: [PATCH 621/663] [docs] Drop a word based on reviewer feedback --- userdocs/diagnostics/protocol-type-non-conformance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md index d3dbadfdf6eb6..11771460941e1 100644 --- a/userdocs/diagnostics/protocol-type-non-conformance.md +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -60,7 +60,7 @@ When used as a type, the Swift protocol `Error` conforms to itself; `@objc` prot Concrete types that _do_ conform to protocols can provide functionality similar to that of existential types. For example, the standard library provides the `AnyHashable` type for `Hashable` values. Manual implementation of such __type erasure__ can require specific knowledge of the semantic requirements for each protocol involved and is beyond the scope of this discussion. -In certain scenarios, you might avoid any need for manual type erasure by reworking generic APIs themselves to use existential types instead: +In certain scenarios, you might avoid any need for manual type erasure by reworking generic APIs to use existential types instead: ```swift func declareAnimalSpeciesDynamically(_ animal: Animal) { From 0f18948bd53a5935caa216859fcce9fa460539ce Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Sun, 6 Sep 2020 23:30:25 -0700 Subject: [PATCH 622/663] [Concurrency] Allow @objc async methods. Allow the declaration of @objc async methods, mapping them to a completion-handler API in Objective-C. This covers most of the checking and semantics within the type checker: * Declaring @objc async methods and checking their parameter/result types * Determining the default Objective-C selector by adding completionHandler/WithCompletionHandler as appropriate * Determining the type of the completion handler parameter * Inferring @objc from protocol requirements * Inferring @objc from an overridden method --- include/swift/AST/DiagnosticsSema.def | 13 ++ include/swift/AST/ForeignAsyncConvention.h | 85 +++++++--- lib/AST/ASTDumper.cpp | 11 ++ lib/AST/ASTVerifier.cpp | 18 +- lib/AST/Decl.cpp | 29 +++- lib/ClangImporter/ImportDecl.cpp | 14 +- lib/ClangImporter/ImportName.cpp | 10 +- lib/ClangImporter/ImportName.h | 6 +- lib/ClangImporter/ImportType.cpp | 16 +- lib/ClangImporter/ImporterImpl.h | 1 + lib/Sema/CodeSynthesis.cpp | 3 +- lib/Sema/TypeCheckCaptures.cpp | 3 +- lib/Sema/TypeCheckDeclObjC.cpp | 187 +++++++++++++++++---- lib/Sema/TypeCheckDeclPrimary.cpp | 9 +- lib/Sema/TypeCheckObjC.h | 2 + test/attr/attr_cdecl_async.swift | 5 + test/attr/attr_objc_async.swift | 18 +- test/decl/async/objc.swift | 44 +++++ 18 files changed, 387 insertions(+), 87 deletions(-) create mode 100644 test/attr/attr_cdecl_async.swift create mode 100644 test/decl/async/objc.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 7977c030ba0c6..82cc9b8ace2f2 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1384,6 +1384,8 @@ ERROR(cdecl_empty_name,none, "@_cdecl symbol name cannot be empty", ()) ERROR(cdecl_throws,none, "raising errors from @_cdecl functions is not supported", ()) +ERROR(cdecl_async,none, + "@_cdecl functions cannot be asynchronous", ()) ERROR(attr_methods_only,none, "only methods can be declared %0", (DeclAttribute)) @@ -4117,6 +4119,17 @@ ERROR(asynchandler_mutating,none, "'@asyncHandler' function cannot be 'mutating'", ()) +ERROR(objc_ambiguous_async_convention,none, + "%0 overrides or implements protocol requirements for Objective-C " + "declarations with incompatible async conventions", + (DeclName)) +NOTE(objc_ambiguous_async_convention_candidate,none, + "%0 provides async here", (DeclName)) + +ERROR(satisfy_async_objc,none, + "satisfying an asychronous @objc %select{method|initializer}0 with " + "a synchronous %select{method|initializer}0 is not supported", (bool)) + //------------------------------------------------------------------------------ // MARK: Type Check Types //------------------------------------------------------------------------------ diff --git a/include/swift/AST/ForeignAsyncConvention.h b/include/swift/AST/ForeignAsyncConvention.h index f3657766e02af..35b6c64b6304c 100644 --- a/include/swift/AST/ForeignAsyncConvention.h +++ b/include/swift/AST/ForeignAsyncConvention.h @@ -24,38 +24,78 @@ namespace swift { /// A small structure describing the async convention of a foreign declaration. class ForeignAsyncConvention { - /// The index of the completion handler parameters. - unsigned CompletionHandlerParamIndex; - - /// When non-zero, indicates which parameter to the completion handler is the - /// Error? parameter (minus one) that makes this async function also throwing. - unsigned CompletionHandlerErrorParamIndex; public: - ForeignAsyncConvention() + struct Info { + /// The index of the completion handler parameters. + unsigned CompletionHandlerParamIndex; + + /// When non-zero, indicates which parameter to the completion handler is + /// the Error? parameter (minus one) that makes this async function also + /// throwing. + unsigned CompletionHandlerErrorParamIndex; + + Info() : CompletionHandlerParamIndex(0), CompletionHandlerErrorParamIndex(0) { } - ForeignAsyncConvention(unsigned completionHandlerParamIndex, - Optional completionHandlerErrorParamIndex) + Info( + unsigned completionHandlerParamIndex, + Optional completionHandlerErrorParamIndex) : CompletionHandlerParamIndex(completionHandlerParamIndex), CompletionHandlerErrorParamIndex( - completionHandlerErrorParamIndex - ? *completionHandlerErrorParamIndex + 1 - : 0) {} + completionHandlerErrorParamIndex + ? *completionHandlerErrorParamIndex + 1 + : 0) {} + + /// Retrieve the index of the \c Error? parameter in the completion handler's + /// parameter list. When argument passed to this parameter is non-null, the + /// provided error will be thrown by the async function. + Optional completionHandlerErrorParamIndex() const { + if (CompletionHandlerErrorParamIndex == 0) + return None; + + return CompletionHandlerErrorParamIndex - 1; + } + + /// Whether the async function is throwing due to the completion handler + /// having an \c Error? parameter. + /// + /// Equivalent to \c static_cast(completionHandlerErrorParamIndex()). + bool isThrowing() const { + return CompletionHandlerErrorParamIndex != 0; + } + }; + + /// The type of the completion handler parameter. + CanType CompletionHandlerType; + + /// Information about the async convention that can be determined from an + /// Objective-C declaration by itself. + Info TheInfo; + +public: + ForeignAsyncConvention() : TheInfo() { } + + ForeignAsyncConvention(CanType completionHandlerType, + unsigned completionHandlerParamIndex, + Optional completionHandlerErrorParamIndex) + : CompletionHandlerType(completionHandlerType), + TheInfo(completionHandlerParamIndex, completionHandlerErrorParamIndex) + { } + + /// Retrieve the type of the completion handler parameter. + CanType completionHandlerType() const { return CompletionHandlerType; } /// Retrieve the index of the completion handler parameter, which will be /// erased from the Swift signature of the imported async function. unsigned completionHandlerParamIndex() const { - return CompletionHandlerParamIndex; + return TheInfo.CompletionHandlerParamIndex; } /// Retrieve the index of the \c Error? parameter in the completion handler's /// parameter list. When argument passed to this parameter is non-null, the /// provided error will be thrown by the async function. Optional completionHandlerErrorParamIndex() const { - if (CompletionHandlerErrorParamIndex == 0) - return None; - - return CompletionHandlerErrorParamIndex - 1; + return TheInfo.completionHandlerErrorParamIndex(); } /// Whether the async function is throwing due to the completion handler @@ -63,14 +103,17 @@ class ForeignAsyncConvention { /// /// Equivalent to \c static_cast(completionHandlerErrorParamIndex()). bool isThrowing() const { - return CompletionHandlerErrorParamIndex != 0; + return TheInfo.isThrowing(); } bool operator==(ForeignAsyncConvention other) const { - return CompletionHandlerParamIndex == other.CompletionHandlerParamIndex - && CompletionHandlerErrorParamIndex == - other.CompletionHandlerErrorParamIndex; + return CompletionHandlerType == other.CompletionHandlerType + && TheInfo.CompletionHandlerParamIndex == + other.TheInfo.CompletionHandlerParamIndex + && TheInfo.CompletionHandlerErrorParamIndex == + other.TheInfo.CompletionHandlerErrorParamIndex; } + bool operator!=(ForeignAsyncConvention other) const { return !(*this == other); } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index caf25cf5dada0..f1544695fc82e 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" @@ -955,6 +956,16 @@ namespace { D->getCaptureInfo().print(OS); } + if (auto fac = D->getForeignAsyncConvention()) { + OS << " foreign_async="; + if (auto type = fac->completionHandlerType()) + type.print(OS); + OS << ",completion_handler_param=" + << fac->completionHandlerParamIndex(); + if (auto errorParamIndex = fac->completionHandlerErrorParamIndex()) + OS << ",error_param=" << *errorParamIndex; + } + if (auto fec = D->getForeignErrorConvention()) { OS << " foreign_error="; OS << getForeignErrorConventionKindString(fec->getKind()); diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index aebc89a1c267a..78ce70008c8ea 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" @@ -2994,8 +2995,23 @@ class Verifier : public ASTWalker { } } - // Throwing @objc methods must have a foreign error convention. + // Asynchronous @objc methods must have a foreign async convention. if (AFD->isObjC() && + static_cast(AFD->getForeignAsyncConvention()) + != AFD->hasAsync()) { + if (AFD->hasAsync()) + Out << "@objc method async but does not have a foreign async " + << "convention"; + else + Out << "@objc method has a foreign async convention but is not " + << "async"; + abort(); + } + + // Synchronous throwing @objc methods must have a foreign error + // convention. + if (AFD->isObjC() && + !AFD->hasAsync() && static_cast(AFD->getForeignErrorConvention()) != AFD->hasThrows()) { if (AFD->hasThrows()) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 03c3111ad8e31..60f13ba3d9fd9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -24,6 +24,7 @@ #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" @@ -6910,10 +6911,13 @@ AbstractFunctionDecl::getObjCSelector(DeclName preferredName, } // The number of selector pieces we'll have. + Optional asyncConvention + = getForeignAsyncConvention(); Optional errorConvention = getForeignErrorConvention(); unsigned numSelectorPieces - = argNames.size() + (errorConvention.hasValue() ? 1 : 0); + = argNames.size() + (asyncConvention.hasValue() ? 1 : 0) + + (errorConvention.hasValue() ? 1 : 0); // If we have no arguments, it's a nullary selector. if (numSelectorPieces == 0) { @@ -6932,6 +6936,14 @@ AbstractFunctionDecl::getObjCSelector(DeclName preferredName, unsigned argIndex = 0; for (unsigned piece = 0; piece != numSelectorPieces; ++piece) { if (piece > 0) { + // If we have an async convention that inserts a completion handler + // parameter here, add "completionHandler". + if (asyncConvention && + piece == asyncConvention->completionHandlerParamIndex()) { + selectorPieces.push_back(ctx.getIdentifier("completionHandler")); + continue; + } + // If we have an error convention that inserts an error parameter // here, add "error". if (errorConvention && @@ -6945,12 +6957,21 @@ AbstractFunctionDecl::getObjCSelector(DeclName preferredName, continue; } - // For the first selector piece, attach either the first parameter - // or "AndReturnError" to the base name, if appropriate. + // For the first selector piece, attach either the first parameter, + // "withCompletionHandker", or "AndReturnError" to the base name, + // if appropriate. auto firstPiece = baseName; llvm::SmallString<32> scratch; scratch += firstPiece.str(); - if (errorConvention && piece == errorConvention->getErrorParameterIndex()) { + if (asyncConvention && + piece == asyncConvention->completionHandlerParamIndex()) { + // The completion handler is first; append "WithCompletionHandler". + camel_case::appendSentenceCase(scratch, "WithCompletionHandler"); + + firstPiece = ctx.getIdentifier(scratch); + didStringManipulation = true; + } else if (errorConvention && + piece == errorConvention->getErrorParameterIndex()) { // The error is first; append "AndReturnError". camel_case::appendSentenceCase(scratch, "AndReturnError"); diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index b61bf24376e08..db5dd761a2ebe 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -4380,6 +4380,7 @@ namespace { kind = SpecialMethodKind::NSDictionarySubscriptGetter; // Import the type that this method will have. + Optional asyncConvention; Optional errorConvention; // If we have a property accessor, find the corresponding property @@ -4418,7 +4419,7 @@ namespace { importedType = Impl.importMethodParamsAndReturnType( dc, decl, decl->parameters(), decl->isVariadic(), isInSystemModule(dc), &bodyParams, importedName, - errorConvention, kind); + asyncConvention, errorConvention, kind); } if (!importedType) return nullptr; @@ -4440,10 +4441,10 @@ namespace { // Determine whether the function is throwing and/or async. bool throws = importedName.getErrorInfo().hasValue(); bool async = false; - auto asyncConvention = importedName.getAsyncInfo(); - if (asyncConvention) { + auto asyncInfo = importedName.getAsyncInfo(); + if (asyncInfo) { async = true; - if (asyncConvention->isThrowing()) + if (asyncInfo->isThrowing()) throws = true; } @@ -6381,11 +6382,14 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( assert(ownerNominal && "Method in non-type context?"); // Import the type that this method will have. + Optional asyncConvention; Optional errorConvention; ParameterList *bodyParams; auto importedType = Impl.importMethodParamsAndReturnType( dc, objcMethod, args, variadic, isInSystemModule(dc), &bodyParams, - importedName, errorConvention, SpecialMethodKind::Constructor); + importedName, asyncConvention, errorConvention, + SpecialMethodKind::Constructor); + assert(!asyncConvention && "Initializers don't have async conventions"); if (!importedType) return nullptr; diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index ff95d8a106441..972e9ca887bf7 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1185,7 +1185,7 @@ static bool isNullableNSErrorType( return true; } -Optional +Optional NameImporter::considerAsyncImport( const clang::ObjCMethodDecl *clangDecl, StringRef &baseName, @@ -1211,7 +1211,8 @@ NameImporter::considerAsyncImport( // Determine whether the naming indicates that this is a completion // handler. Optional newBaseName; - if (isCompletionHandlerParamName(paramNames[completionHandlerParamNameIndex])) { + if (isCompletionHandlerParamName( + paramNames[completionHandlerParamNameIndex])) { // The argument label itself has an appropriate name. } else if (!hasCustomName && completionHandlerParamIndex == 0 && (newBaseName = isCompletionHandlerInBaseName(baseName))) { @@ -1226,7 +1227,8 @@ NameImporter::considerAsyncImport( // Used for returns once we've determined that the method cannot be // imported as async, even though it has what looks like a completion handler // parameter. - auto notAsync = [&](const char *reason) -> Optional { + auto notAsync = [&](const char *reason) -> + Optional { #ifdef ASYNC_IMPORT_DEBUG llvm::errs() << "*** failed async import: " << reason << "\n"; clangDecl->dump(llvm::errs()); @@ -1306,7 +1308,7 @@ NameImporter::considerAsyncImport( if (newBaseName && !hasCustomName) baseName = *newBaseName; - return ForeignAsyncConvention( + return ForeignAsyncConvention::Info( completionHandlerParamIndex, completionHandlerErrorParamIndex); } diff --git a/lib/ClangImporter/ImportName.h b/lib/ClangImporter/ImportName.h index 09d90703563c9..5f5d9a027343e 100644 --- a/lib/ClangImporter/ImportName.h +++ b/lib/ClangImporter/ImportName.h @@ -200,7 +200,7 @@ class ImportedName { /// For names that map Objective-C completion handlers into async /// Swift methods, describes how the mapping is performed. - ForeignAsyncConvention asyncInfo; + ForeignAsyncConvention::Info asyncInfo; /// For a declaration name that makes the declaration into an /// instance member, the index of the "Self" parameter. @@ -270,7 +270,7 @@ class ImportedName { /// For names that map Objective-C methods with completion handlers into /// async Swift methods, describes how the mapping is performed. - Optional getAsyncInfo() const { + Optional getAsyncInfo() const { if (info.hasAsyncInfo) return info.asyncInfo; return None; @@ -453,7 +453,7 @@ class NameImporter { ArrayRef params, bool isInitializer, bool hasCustomName); - Optional + Optional considerAsyncImport(const clang::ObjCMethodDecl *clangDecl, StringRef &baseName, SmallVectorImpl ¶mNames, diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index b386d03579cef..cec3b65c6b3fd 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1997,7 +1997,7 @@ static Type mapGenericArgs(const DeclContext *fromDC, /// Decompose the type of a completion handler parameter in a function /// imported as 'async' and produce the result type of the 'async' function. static Type decomposeCompletionHandlerType( - Type paramTy, ForeignAsyncConvention info) { + Type paramTy, ForeignAsyncConvention::Info info) { auto fnType = paramTy->lookThroughAllOptionalTypes()->getAs(); if (!fnType) return Type(); @@ -2035,6 +2035,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( ArrayRef params, bool isVariadic, bool isFromSystemModule, ParameterList **bodyParams, ImportedName importedName, + Optional &asyncConvention, Optional &foreignErrorInfo, SpecialMethodKind kind) { @@ -2129,6 +2130,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( swiftResultTy = mapGenericArgs(origDC, dc, swiftResultTy); CanType errorParamType; + CanType completionHandlerType; SmallBitVector nonNullArgs = getNonNullArgs(clangDecl, params); @@ -2166,7 +2168,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( } bool paramIsCompletionHandler = - asyncInfo && paramIndex == asyncInfo->completionHandlerParamIndex(); + asyncInfo && paramIndex == asyncInfo->CompletionHandlerParamIndex; // Import the parameter type into Swift. @@ -2243,9 +2245,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( if (Type replacedSwiftResultTy = decomposeCompletionHandlerType(swiftParamTy, *asyncInfo)) { swiftResultTy = replacedSwiftResultTy; - - // FIXME: We will need an equivalent to "error parameter is replaced" - // for asynchronous functions. Perhaps add "async: ()"? + completionHandlerType = swiftParamTy->getCanonicalType(); continue; } @@ -2340,6 +2340,12 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( swiftResultTy = SwiftContext.getNeverType(); } + if (asyncInfo) { + asyncConvention = ForeignAsyncConvention( + completionHandlerType, asyncInfo->CompletionHandlerParamIndex, + asyncInfo->CompletionHandlerErrorParamIndex); + } + if (errorInfo) { foreignErrorInfo = getForeignErrorInfo(*errorInfo, errorParamType, origSwiftResultTy); diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 79ddfb0938b5f..8ee400018ba1e 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1159,6 +1159,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation bool isFromSystemModule, ParameterList **bodyParams, importer::ImportedName importedName, + Optional &asyncConv, Optional &errorConv, SpecialMethodKind kind); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 5ed7bdafa5de6..384cad9dcb45c 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -550,10 +550,11 @@ configureInheritedDesignatedInitAttributes(ClassDecl *classDecl, // If the superclass constructor is @objc but the subclass constructor is // not representable in Objective-C, add @nonobjc implicitly. + Optional asyncConvention; Optional errorConvention; if (superclassCtor->isObjC() && !isRepresentableInObjC(ctor, ObjCReason::MemberOfObjCSubclass, - errorConvention)) + asyncConvention, errorConvention)) ctor->getAttrs().add(new (ctx) NonObjCAttr(/*isImplicit=*/true)); } diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 20a41c6953b7e..c83ed135bcc9a 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -660,10 +660,11 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { AFD->diagnose(diag::objc_generic_extension_using_type_parameter); // If it's possible, suggest adding @objc. + Optional asyncConvention; Optional errorConvention; if (!AFD->isObjC() && isRepresentableInObjC(AFD, ObjCReason::MemberOfObjCMembersClass, - errorConvention)) { + asyncConvention, errorConvention)) { AFD->diagnose( diag::objc_generic_extension_using_type_parameter_try_objc) .fixItInsert(AFD->getAttributeInsertionLoc(false), "@objc "); diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 7e8c1d45521f8..2571be129ab12 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -494,8 +494,11 @@ static bool isValidObjectiveCErrorResultType(DeclContext *dc, Type type) { bool swift::isRepresentableInObjC( const AbstractFunctionDecl *AFD, ObjCReason Reason, + Optional &asyncConvention, Optional &errorConvention) { - // Clear out the error convention. It will be added later if needed. + // Clear out the async and error conventions. They will be added later if + // needed. + asyncConvention = None; errorConvention = None; // If you change this function, you must add or modify a test in PrintAsObjC. @@ -596,7 +599,8 @@ bool swift::isRepresentableInObjC( if (auto FD = dyn_cast(AFD)) { Type ResultType = FD->mapTypeIntoContext(FD->getResultInterfaceType()); - if (!ResultType->hasError() && + if (!FD->hasAsync() && + !ResultType->hasError() && !ResultType->isVoid() && !ResultType->isUninhabited() && !ResultType->isRepresentableIn(ForeignLanguage::ObjectiveC, @@ -612,18 +616,83 @@ bool swift::isRepresentableInObjC( } } - // Async functions cannot be mapped into Objective-C. if (AFD->hasAsync()) { - if (Diagnose) { - AFD->diagnose(diag::not_objc_function_async) - .highlight(AFD->getAsyncLoc()); - describeObjCReason(AFD, Reason); + // Asynchronous functions move all of the result value and thrown error + // information into a completion handler. + auto FD = dyn_cast(AFD); + if (!FD) { + if (Diagnose) { + AFD->diagnose(diag::not_objc_function_async) + .highlight(AFD->getAsyncLoc()); + describeObjCReason(AFD, Reason); + } + + return false; + } + + // The completion handler parameter always goes at the end. + unsigned completionHandlerParamIndex = AFD->getParameters()->size(); + + // Decompose the return type to form the parameter type of the completion + // handler. + SmallVector completionHandlerParams; + auto addCompletionHandlerParam = [&](Type type) { + // For a throwing asynchronous function, make each parameter type optional + // if that's representable in Objective-C. + if (AFD->hasThrows() && + !type->getOptionalObjectType() && + isValidObjectiveCErrorResultType(const_cast(FD), type)) { + type = OptionalType::get(type); + } + + completionHandlerParams.push_back(AnyFunctionType::Param(type)); + + // Make sure that the paraneter type is representable in Objective-C. + if (!type->isRepresentableIn( + ForeignLanguage::ObjectiveC, const_cast(FD))) { + if (Diagnose) { + AFD->diagnose(diag::objc_invalid_on_func_result_type, + getObjCDiagnosticAttrKind(Reason)); + diagnoseTypeNotRepresentableInObjC(FD, type, + FD->getResultTypeSourceRange()); + describeObjCReason(FD, Reason); + } + + return true; + } + + return false; + }; + + // Translate the result type of the function into parameters for the + // completion handler parameter, exploding one level of tuple if needed. + Type resultType = FD->mapTypeIntoContext(FD->getResultInterfaceType()); + if (auto tupleType = resultType->getAs()) { + for (const auto &tupleElt : tupleType->getElements()) { + addCompletionHandlerParam(tupleElt.getType()); + } + } else { + addCompletionHandlerParam(resultType); } - return false; - } - // Throwing functions must map to a particular error convention. - if (AFD->hasThrows()) { + // For a throwing asynchronous function, an Error? parameter is added + // to the completion handler parameter, and will be non-nil to signal + // a thrown error. + Optional completionHandlerErrorParamIndex; + if (FD->hasThrows()) { + completionHandlerErrorParamIndex = completionHandlerParams.size(); + addCompletionHandlerParam(OptionalType::get(ctx.getExceptionType())); + } + + Type completionHandlerType = FunctionType::get( + completionHandlerParams, TupleType::getEmpty(ctx), + ASTExtInfoBuilder(FunctionTypeRepresentation::Block, false).build()); + + asyncConvention = ForeignAsyncConvention( + completionHandlerType->getCanonicalType(), completionHandlerParamIndex, + completionHandlerErrorParamIndex); + } else if (AFD->hasThrows()) { + // Synchronous throwing functions must map to a particular error convention. DeclContext *dc = const_cast(AFD); SourceLoc throwsLoc; Type resultType; @@ -947,9 +1016,10 @@ bool swift::canBeRepresentedInObjC(const ValueDecl *decl) { return false; if (auto func = dyn_cast(decl)) { + Optional asyncConvention; Optional errorConvention; return isRepresentableInObjC(func, ObjCReason::MemberOfObjCMembersClass, - errorConvention); + asyncConvention, errorConvention); } if (auto var = dyn_cast(decl)) @@ -1306,6 +1376,7 @@ static bool isEnumObjC(EnumDecl *enumDecl) { /// Record that a declaration is @objc. static void markAsObjC(ValueDecl *D, ObjCReason reason, + Optional asyncConvention, Optional errorConvention); @@ -1393,6 +1464,7 @@ bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const { } // If needed, check whether this declaration is representable in Objective-C. + Optional asyncConvention; Optional errorConvention; if (auto var = dyn_cast(VD)) { if (!isRepresentableInObjC(var, *isObjC)) { @@ -1407,14 +1479,15 @@ bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const { } else if (isa(VD)) { // Destructors need no additional checking. } else if (auto func = dyn_cast(VD)) { - if (!isRepresentableInObjC(func, *isObjC, errorConvention)) { + if (!isRepresentableInObjC( + func, *isObjC, asyncConvention, errorConvention)) { makeNotObjC(); return false; } } // Note that this declaration is exposed to Objective-C. - markAsObjC(VD, *isObjC, errorConvention); + markAsObjC(VD, *isObjC, asyncConvention, errorConvention); return true; } @@ -1570,6 +1643,7 @@ static ObjCSelector inferObjCName(ValueDecl *decl) { /// If the declaration has a @nonobjc attribute, diagnose an error /// using the given Reason, if present. void markAsObjC(ValueDecl *D, ObjCReason reason, + Optional asyncConvention, Optional errorConvention) { ASTContext &ctx = D->getASTContext(); @@ -1587,19 +1661,28 @@ void markAsObjC(ValueDecl *D, ObjCReason reason, } if (auto method = dyn_cast(D)) { - // Determine the foreign error convention. - Optional inheritedConvention; - AbstractFunctionDecl *declProvidingInheritedConvention = nullptr; + // Determine the foreign async and error conventions. + Optional inheritedAsyncConvention; + AbstractFunctionDecl *declProvidingInheritedAsyncConvention = nullptr; + Optional inheritedErrorConvention; + AbstractFunctionDecl *declProvidingInheritedErrorConvention = nullptr; if (auto baseMethod = method->getOverriddenDecl()) { - // If the overridden method has a foreign error convention, - // adopt it. Set the foreign error convention for a throwing - // method. Note that the foreign error convention affects the + // If the overridden method has a foreign async or error convention, + // adopt it. Note that the foreign async or error convention affects the // selector, so we perform this before inferring a selector. + if (method->hasAsync()) { + if (auto baseAsyncConvention + = baseMethod->getForeignAsyncConvention()) { + inheritedAsyncConvention = baseAsyncConvention; + declProvidingInheritedAsyncConvention = baseMethod; + } + } + if (method->hasThrows()) { if (auto baseErrorConvention = baseMethod->getForeignErrorConvention()) { - inheritedConvention = baseErrorConvention; - declProvidingInheritedConvention = baseMethod; + inheritedErrorConvention = baseErrorConvention; + declProvidingInheritedErrorConvention = baseMethod; } } } @@ -1607,42 +1690,78 @@ void markAsObjC(ValueDecl *D, ObjCReason reason, for (auto req : findWitnessedObjCRequirements(method)) { auto reqMethod = dyn_cast(req); if (!reqMethod) continue; - + + // If the method witnesses an ObjC requirement that is async, adopt its + // async convention. + if (reqMethod->hasAsync()) { + if (auto reqAsyncConvention = reqMethod->getForeignAsyncConvention()) { + // Check for a conflict among protocol conformances or inherited + // methods. + if (declProvidingInheritedAsyncConvention + && inheritedAsyncConvention != reqAsyncConvention) { + method->diagnose(diag::objc_ambiguous_async_convention, + method->getName()); + declProvidingInheritedAsyncConvention->diagnose( + diag::objc_ambiguous_async_convention_candidate, + declProvidingInheritedAsyncConvention->getName()); + reqMethod->diagnose(diag::objc_ambiguous_async_convention_candidate, + reqMethod->getName()); + break; + } + + inheritedAsyncConvention = reqAsyncConvention; + declProvidingInheritedAsyncConvention = reqMethod; + } + } + // If the method witnesses an ObjC requirement that throws, adopt its // error convention. if (reqMethod->hasThrows()) { if (auto reqErrorConvention = reqMethod->getForeignErrorConvention()) { // Check for a conflict among protocol conformances or inherited // methods. - if (declProvidingInheritedConvention - && inheritedConvention != reqErrorConvention) { + if (declProvidingInheritedErrorConvention + && inheritedErrorConvention != reqErrorConvention) { method->diagnose(diag::objc_ambiguous_error_convention, method->getName()); - declProvidingInheritedConvention->diagnose( - diag::objc_ambiguous_error_convention_candidate, - declProvidingInheritedConvention->getName()); + declProvidingInheritedErrorConvention->diagnose( + diag::objc_ambiguous_error_convention_candidate, + declProvidingInheritedErrorConvention->getName()); reqMethod->diagnose(diag::objc_ambiguous_error_convention_candidate, reqMethod->getName()); break; } - inheritedConvention = reqErrorConvention; - declProvidingInheritedConvention = reqMethod; + inheritedErrorConvention = reqErrorConvention; + declProvidingInheritedErrorConvention = reqMethod; } } } + // Attach the foreign async convention. + if (inheritedAsyncConvention) { + if (!method->hasAsync()) + method->diagnose(diag::satisfy_async_objc, + isa(method)); + else + method->setForeignAsyncConvention(*inheritedAsyncConvention); + + } else if (method->hasAsync()) { + assert(asyncConvention && "Missing async convention"); + method->setForeignAsyncConvention(*asyncConvention); + } + // Attach the foreign error convention. - if (inheritedConvention) { + if (inheritedErrorConvention) { // Diagnose if this is a method that does not throw - // but inherits an ObjC error convention. + // but inherits an ObjC error convention. if (!method->hasThrows()) method->diagnose(diag::satisfy_throws_objc, isa(method)); else - method->setForeignErrorConvention(*inheritedConvention); + method->setForeignErrorConvention(*inheritedErrorConvention); - } else if (method->hasThrows()) { + } else if (method->hasThrows() && !method->hasAsync()) { assert(errorConvention && "Missing error convention"); method->setForeignErrorConvention(*errorConvention); } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index a342b4ff067b2..e999479912259 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2347,10 +2347,15 @@ class DeclChecker : public DeclVisitor { // FIXME: This needs to be moved to its own request if we want to // productize @_cdecl. if (auto CDeclAttr = FD->getAttrs().getAttribute()) { + Optional asyncConvention; Optional errorConvention; if (isRepresentableInObjC(FD, ObjCReason::ExplicitlyCDecl, - errorConvention)) { - if (FD->hasThrows()) { + asyncConvention, errorConvention)) { + if (FD->hasAsync()) { + FD->setForeignAsyncConvention(*asyncConvention); + getASTContext().Diags.diagnose(CDeclAttr->getLocation(), + diag::cdecl_async); + } else if (FD->hasThrows()) { FD->setForeignErrorConvention(*errorConvention); getASTContext().Diags.diagnose(CDeclAttr->getLocation(), diag::cdecl_throws); diff --git a/lib/Sema/TypeCheckObjC.h b/lib/Sema/TypeCheckObjC.h index 808bb9118c467..41a08f1fafd70 100644 --- a/lib/Sema/TypeCheckObjC.h +++ b/lib/Sema/TypeCheckObjC.h @@ -17,6 +17,7 @@ #ifndef SWIFT_SEMA_TYPE_CHECK_OBJC_H #define SWIFT_SEMA_TYPE_CHECK_OBJC_H +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "llvm/ADT/Optional.h" @@ -123,6 +124,7 @@ unsigned getObjCDiagnosticAttrKind(ObjCReason reason); /// and figure out its foreign error convention (if any). bool isRepresentableInObjC(const AbstractFunctionDecl *AFD, ObjCReason Reason, + Optional &asyncConvention, Optional &errorConvention); /// Determine whether the given variable can be represented in Objective-C. diff --git a/test/attr/attr_cdecl_async.swift b/test/attr/attr_cdecl_async.swift new file mode 100644 index 0000000000000..2cf765e8da20f --- /dev/null +++ b/test/attr/attr_cdecl_async.swift @@ -0,0 +1,5 @@ +// RUN: %target-typecheck-verify-swift -enable-objc-interop -enable-experimental-concurrency + +@_cdecl("async") // expected-error{{@_cdecl functions cannot be asynchronous}} +func asynchronous() async { } + diff --git a/test/attr/attr_objc_async.swift b/test/attr/attr_objc_async.swift index ba80dceb739c1..a65180bd9040c 100644 --- a/test/attr/attr_objc_async.swift +++ b/test/attr/attr_objc_async.swift @@ -1,13 +1,19 @@ -// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency -// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency | %FileCheck %s -// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 4 -enable-source-import -I %S/Inputs -enable-swift3-objc-inference -enable-experimental-concurrency > %t.ast +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify -verify-ignore-unknown %s -swift-version 5 -enable-source-import -I %S/Inputs -enable-experimental-concurrency +// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 5 -enable-source-import -I %S/Inputs -enable-experimental-concurrency | %FileCheck %s +// RUN: not %target-swift-frontend -typecheck -dump-ast -disable-objc-attr-requires-foundation-module %s -swift-version 5 -enable-source-import -I %S/Inputs -enable-experimental-concurrency > %t.ast // RUN: %FileCheck -check-prefix CHECK-DUMP %s < %t.ast // REQUIRES: objc_interop +import Foundation -// async cannot be compiled with @objc. -// CHECK-DUMP: class Concurrency +// CHECK: class Concurrency class Concurrency { - @objc func doBigJob() async -> Int { return 0 } // expected-error{{'async' function cannot be represented in Objective-C}} + // CHECK: @objc func doBigJob() async -> Int + // CHECK-DUMP: func_decl{{.*}}doBigJob{{.*}}foreign_async=@convention(block) (Int) -> (),completion_handler_param=0 + @objc func doBigJob() async -> Int { return 0 } + + // CHECK: @objc func doBigJobOrFail(_: Int) async throws -> (AnyObject, Int) + // CHECK-DUMP: func_decl{{.*}}doBigJobOrFail{{.*}}foreign_async=@convention(block) (Optional, Int, Optional) -> (),completion_handler_param=1,error_param=2 + @objc func doBigJobOrFail(_: Int) async throws -> (AnyObject, Int) { return (self, 0) } @objc func takeAnAsync(_ fn: () async -> Int) { } // expected-error{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}} // expected-note@-1{{'async' function types cannot be represented in Objective-C}} diff --git a/test/decl/async/objc.swift b/test/decl/async/objc.swift new file mode 100644 index 0000000000000..96fba77b9826b --- /dev/null +++ b/test/decl/async/objc.swift @@ -0,0 +1,44 @@ +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s -swift-version 5 -enable-experimental-concurrency +// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=true -prefer-type-repr=false -print-implicit-attrs=true -explode-pattern-binding-decls=true -disable-objc-attr-requires-foundation-module -swift-version 5 -enable-experimental-concurrency | %FileCheck %s +// REQUIRES: objc_interop +import Foundation +import ObjectiveC + +@objc protocol P { + func doBigJob() async -> Int +} + +// Infer @objc from protocol conformance +// CHECK: class ConformsToP +class ConformsToP: P { + // CHECK: @objc func doBigJob() async -> Int + func doBigJob() async -> Int { 5 } +} + +// Infer @objc from superclass +class Super { + @objc func longRunningRequest() async throws -> [String] { [] } +} + +// CHECK: class Sub +class Sub : Super { + // CHECK-NEXT: @objc override func longRunningRequest() async throws -> [String] + override func longRunningRequest() async throws -> [String] { [] } +} + +// Check selector computation. +@objc protocol MakeSelectors { + func selectorAsync() async -> Int + func selector(value: Int) async -> Int +} + +func testSelectors() { + // expected-warning@+1{{use '#selector' instead of explicitly constructing a 'Selector'}} + _ = Selector("selectorAsyncWithCompletionHandler:") + + // expected-warning@+1{{use '#selector' instead of explicitly constructing a 'Selector'}} + _ = Selector("selectorWithValue:completionHandler:") + + _ = Selector("canary:") // expected-warning{{no method declared with Objective-C selector 'canary:'}} + // expected-note@-1{{wrap the selector name in parentheses to suppress this warning}} +} From daf9e2df7efcb18634e7533b7e10ff00566886c3 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Sun, 6 Sep 2020 23:49:57 -0700 Subject: [PATCH 623/663] [Concurrency] Print @objc async declarations as Objective-C declarations. @objc async declarations are mapping into completion-handler-based methods in Objective-C, so ensure that the result type, parameters, and attributes reflect that. --- lib/PrintAsObjC/DeclAndTypePrinter.cpp | 34 +++++++++++++++++++++++--- test/PrintAsObjC/async.swift | 30 +++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 test/PrintAsObjC/async.swift diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 3a84f5cc82bcc..d380fec22edf5 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -18,6 +18,7 @@ #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/PrettyStackTrace.h" @@ -464,6 +465,7 @@ class DeclAndTypePrinter::Implementation Type getForeignResultType(AbstractFunctionDecl *AFD, FunctionType *methodTy, + Optional asyncConvention, Optional errorConvention) { // A foreign error convention can affect the result type as seen in // Objective-C. @@ -484,6 +486,11 @@ class DeclAndTypePrinter::Implementation } } + // Asynchronous methods return their results via completion handler. + if (asyncConvention) { + return getASTContext().TheEmptyTupleType; + } + auto result = methodTy->getResult(); if (result->isUninhabited()) return getASTContext().TheEmptyTupleType; @@ -513,16 +520,20 @@ class DeclAndTypePrinter::Implementation } } + Optional asyncConvention + = AFD->getForeignAsyncConvention(); Optional errorConvention = AFD->getForeignErrorConvention(); Type rawMethodTy = AFD->getMethodInterfaceType(); auto methodTy = rawMethodTy->castTo(); - auto resultTy = getForeignResultType(AFD, methodTy, errorConvention); + auto resultTy = getForeignResultType( + AFD, methodTy, asyncConvention, errorConvention); // Constructors and methods returning DynamicSelf return // instancetype. if (isa(AFD) || - (isa(AFD) && cast(AFD)->hasDynamicSelfResult())) { + (isa(AFD) && cast(AFD)->hasDynamicSelfResult() && + !AFD->hasAsync())) { if (errorConvention && errorConvention->stripsResultOptionality()) { printNullability(OTK_Optional, NullabilityPrintKind::ContextSensitive); } else if (auto ctor = dyn_cast(AFD)) { @@ -578,6 +589,16 @@ class DeclAndTypePrinter::Implementation StringRef piece = selectorPieces[i].empty() ? StringRef("") : selectorPieces[i].str(); + // If we have an async convention and this is the completion handler + // parameter, print it. + if (asyncConvention && + i == asyncConvention->completionHandlerParamIndex()) { + os << piece << ":("; + print(asyncConvention->completionHandlerType(), None); + os << ")completionHandler"; + continue; + } + // If we have an error convention and this is the error // parameter, print it. if (errorConvention && i == errorConvention->getErrorParameterIndex()) { @@ -660,7 +681,9 @@ class DeclAndTypePrinter::Implementation if (looksLikeInitMethod(AFD->getObjCSelector())) { os << " SWIFT_METHOD_FAMILY(none)"; } - if (methodTy->getResult()->isUninhabited()) { + if (asyncConvention) { + // Async methods don't have result types to annotate. + } else if (methodTy->getResult()->isUninhabited()) { os << " SWIFT_NORETURN"; } else if (!methodTy->getResult()->isVoid() && !AFD->getAttrs().hasAttribute()) { @@ -697,12 +720,15 @@ class DeclAndTypePrinter::Implementation void printAbstractFunctionAsFunction(FuncDecl *FD) { printDocumentationComment(FD); + Optional asyncConvention + = FD->getForeignAsyncConvention(); Optional errorConvention = FD->getForeignErrorConvention(); assert(!FD->getGenericSignature() && "top-level generic functions not supported here"); auto funcTy = FD->getInterfaceType()->castTo(); - auto resultTy = getForeignResultType(FD, funcTy, errorConvention); + auto resultTy = getForeignResultType( + FD, funcTy, asyncConvention, errorConvention); // The result type may be a partial function type we need to close // up later. diff --git a/test/PrintAsObjC/async.swift b/test/PrintAsObjC/async.swift new file mode 100644 index 0000000000000..bfa69136a9e54 --- /dev/null +++ b/test/PrintAsObjC/async.swift @@ -0,0 +1,30 @@ +// REQUIRES: objc_interop + +// RUN: %empty-directory(%t) + +// FIXME: BEGIN -enable-source-import hackaround +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift -disable-objc-attr-requires-foundation-module +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/Foundation.swift +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/AppKit.swift +// FIXME: END -enable-source-import hackaround + + +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -parse-as-library %s -typecheck -I %S/Inputs/custom-modules -emit-objc-header-path %t/async.h -import-objc-header %S/../Inputs/empty.h -enable-experimental-concurrency -typecheck +// RUN: %FileCheck %s < %t/async.h +// RUN: %check-in-clang -I %S/Inputs/custom-modules/ %t/async.h + +import Foundation + +// CHECK-LABEL: @interface BarClass : NSObject +@objc @objcMembers class BarClass: NSObject { + // CHECK: (void)doSomethingBigWithCompletionHandler:(void (^)(NSInteger))completionHandler; + func doSomethingBig() async -> Int { 0 } + + // CHECK: - (void)longRunningWithString:(NSString * _Nonnull)string completionHandler:(void (^)(BarClass * _Nullable, NSError * _Nullable))completionHandler; + func longRunning(string: String) async throws -> BarClass { return self } + + // CHECK: - (void)magicTupleReturnWithCompletionHandler:(void (^)(BarClass * _Nonnull, NSInteger))completionHandler; + func magicTupleReturn() async -> (BarClass, Int) { return (self, 0) } +} +// CHECK: @end From 8dc8532965ff79c388f5840babb5654b498e5bbc Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 7 Sep 2020 21:20:16 -0700 Subject: [PATCH 624/663] [Concurrency] Ban asynchronous methods returning 'Self' from being @objc --- include/swift/AST/DiagnosticsSema.def | 2 ++ lib/Sema/TypeCheckDeclObjC.cpp | 12 ++++++++++++ test/attr/attr_objc_async.swift | 3 +++ 3 files changed, 17 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 82cc9b8ace2f2..b17de15fe717f 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4129,6 +4129,8 @@ NOTE(objc_ambiguous_async_convention_candidate,none, ERROR(satisfy_async_objc,none, "satisfying an asychronous @objc %select{method|initializer}0 with " "a synchronous %select{method|initializer}0 is not supported", (bool)) +ERROR(async_objc_dynamic_self,none, + "asynchronous method returning 'Self' cannot be '@objc'", ()) //------------------------------------------------------------------------------ // MARK: Type Check Types diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 2571be129ab12..617cb07357fa6 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -630,6 +630,18 @@ bool swift::isRepresentableInObjC( return false; } + // The completion handler transformation cannot properly represent a + // dynamic 'Self' type, so disallow @objc for such methods. + if (FD->hasDynamicSelfResult()) { + if (Diagnose) { + AFD->diagnose(diag::async_objc_dynamic_self) + .highlight(AFD->getAsyncLoc()); + describeObjCReason(AFD, Reason); + } + + return false; + } + // The completion handler parameter always goes at the end. unsigned completionHandlerParamIndex = AFD->getParameters()->size(); diff --git a/test/attr/attr_objc_async.swift b/test/attr/attr_objc_async.swift index a65180bd9040c..a3a2aad0c459d 100644 --- a/test/attr/attr_objc_async.swift +++ b/test/attr/attr_objc_async.swift @@ -17,4 +17,7 @@ class Concurrency { @objc func takeAnAsync(_ fn: () async -> Int) { } // expected-error{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}} // expected-note@-1{{'async' function types cannot be represented in Objective-C}} + + @objc class func createAsynchronously() async -> Self? { nil } + // expected-error@-1{{asynchronous method returning 'Self' cannot be '@objc'}} } From ed30712ff36e375350c2ade1343c6aa995d1eedf Mon Sep 17 00:00:00 2001 From: Valeriy Van Date: Tue, 8 Sep 2020 20:36:21 +0200 Subject: [PATCH 625/663] Fixes example snippet in OutputStream.swift (#33844) --- stdlib/public/core/OutputStream.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 7faafbaa27c98..52101107dde33 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -225,10 +225,7 @@ public protocol LosslessStringConvertible: CustomStringConvertible { /// /// let p = Point(x: 21, y: 30) /// print(String(reflecting: p)) -/// // Prints "p: Point = { -/// // x = 21 -/// // y = 30 -/// // }" +/// // Prints "Point(x: 21, y: 30)" /// /// After adding `CustomDebugStringConvertible` conformance by implementing the /// `debugDescription` property, `Point` provides its own custom debugging @@ -236,12 +233,12 @@ public protocol LosslessStringConvertible: CustomStringConvertible { /// /// extension Point: CustomDebugStringConvertible { /// var debugDescription: String { -/// return "Point(x: \(x), y: \(y))" +/// return "(\(x), \(y))" /// } /// } /// /// print(String(reflecting: p)) -/// // Prints "Point(x: 21, y: 30)" +/// // Prints "(21, 30)" public protocol CustomDebugStringConvertible { /// A textual representation of this instance, suitable for debugging. /// From 14e63380f26a74417c2129f6433a5a2abe2d9ce6 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Tue, 8 Sep 2020 18:04:04 -0700 Subject: [PATCH 626/663] [AutoDiff] Generate transparent ossa reabstraction thunks. (#33854) Make the differentiation transform generate transparent, ossa reabstraction thunks. This enables these thunks to be inlined into other ossa functions (e.g. generated VJP and pullback functions) during mandatory inlining. Resolves TF-989. Unblocks further autodiff-related optimizations: SR-13390. --- lib/SILOptimizer/Differentiation/Thunk.cpp | 124 ++++++++++++++++----- 1 file changed, 99 insertions(+), 25 deletions(-) diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index 820805fff06d9..a59dc092302e5 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -249,6 +249,58 @@ CanSILFunctionType buildThunkType(SILFunction *fn, fn->getASTContext()); } +/// Forward function arguments, handling ownership convention mismatches. +/// Adapted from `forwardFunctionArguments` in SILGenPoly.cpp. +/// +/// Forwarded arguments are appended to `forwardedArgs`. +/// +/// Local allocations are appended to `localAllocations`. They need to be +/// deallocated via `dealloc_stack`. +/// +/// Local values requiring cleanup are appended to `valuesToCleanup`. +static void forwardFunctionArgumentsConvertingOwnership( + SILBuilder &builder, SILLocation loc, CanSILFunctionType fromTy, + CanSILFunctionType toTy, ArrayRef originalArgs, + SmallVectorImpl &forwardedArgs, + SmallVectorImpl &localAllocations, + SmallVectorImpl &valuesToCleanup) { + auto fromParameters = fromTy->getParameters(); + auto toParameters = toTy->getParameters(); + assert(fromParameters.size() == toParameters.size()); + assert(fromParameters.size() == originalArgs.size()); + for (auto index : indices(originalArgs)) { + auto &arg = originalArgs[index]; + auto fromParam = fromParameters[index]; + auto toParam = toParameters[index]; + // To convert guaranteed argument to be owned, create a copy. + if (fromParam.isConsumed() && !toParam.isConsumed()) { + // If the argument has an object type, create a `copy_value`. + if (arg->getType().isObject()) { + auto argCopy = builder.emitCopyValueOperation(loc, arg); + forwardedArgs.push_back(argCopy); + continue; + } + // If the argument has an address type, create a local allocation and + // `copy_addr` its contents to the local allocation. + auto *alloc = builder.createAllocStack(loc, arg->getType()); + builder.createCopyAddr(loc, arg, alloc, IsNotTake, IsInitialization); + localAllocations.push_back(alloc); + forwardedArgs.push_back(alloc); + continue; + } + // To convert owned argument to be guaranteed, borrow the argument. + if (fromParam.isGuaranteed() && !toParam.isGuaranteed()) { + auto bbi = builder.emitBeginBorrowOperation(loc, arg); + forwardedArgs.push_back(bbi); + valuesToCleanup.push_back(bbi); + valuesToCleanup.push_back(arg); + continue; + } + // Otherwise, simply forward the argument. + forwardedArgs.push_back(arg); + } +} + SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, SILModule &module, SILLocation loc, SILFunction *caller, @@ -274,18 +326,13 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, thunkType, fromInterfaceType, toInterfaceType, Type(), module.getSwiftModule()); - // FIXME(TF-989): Mark reabstraction thunks as transparent. This requires - // generating ossa reabstraction thunks so that they can be inlined during - // mandatory inlining when `-enable-strip-ownership-after-serialization` is - // true and ownership model eliminator is not run after differentiation. auto *thunk = fb.getOrCreateSharedFunction( - loc, name, thunkDeclType, IsBare, IsNotTransparent, IsSerialized, + loc, name, thunkDeclType, IsBare, IsTransparent, IsSerialized, ProfileCounter(), IsReabstractionThunk, IsNotDynamic); if (!thunk->empty()) return thunk; thunk->setGenericEnvironment(genericEnv); - thunk->setOwnershipEliminated(); auto *entry = thunk->createBasicBlock(); SILBuilder builder(entry); createEntryArguments(thunk); @@ -294,13 +341,21 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, SILFunctionConventions toConv(toType, module); assert(toConv.useLoweredAddresses()); - auto *fnArg = thunk->getArgumentsWithoutIndirectResults().back(); + // Forward thunk arguments, handling ownership convention mismatches. + SmallVector forwardedArgs; + for (auto indRes : thunk->getIndirectResults()) + forwardedArgs.push_back(indRes); + SmallVector localAllocations; + SmallVector valuesToCleanup; + forwardFunctionArgumentsConvertingOwnership( + builder, loc, fromType, toType, + thunk->getArgumentsWithoutIndirectResults().drop_back(), forwardedArgs, + localAllocations, valuesToCleanup); SmallVector arguments; - auto toArgIter = thunk->getArguments().begin(); + auto toArgIter = forwardedArgs.begin(); auto useNextArgument = [&]() { arguments.push_back(*toArgIter++); }; - SmallVector localAllocations; auto createAllocStack = [&](SILType type) { auto *alloc = builder.createAllocStack(loc, type); localAllocations.push_back(alloc); @@ -350,21 +405,25 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, if (!paramTy.hasArchetype()) paramTy = thunk->mapTypeIntoContext(paramTy); assert(paramTy.isAddress()); - auto *toArg = *toArgIter++; + auto toArg = *toArgIter++; auto *buf = createAllocStack(toArg->getType()); - builder.createStore(loc, toArg, buf, - StoreOwnershipQualifier::Unqualified); + toArg = builder.emitCopyValueOperation(loc, toArg); + builder.emitStoreValueOperation(loc, toArg, buf, + StoreOwnershipQualifier::Init); + valuesToCleanup.push_back(buf); arguments.push_back(buf); continue; } // Convert direct parameter to indirect parameter. assert(toParam.isFormalIndirect()); - auto *toArg = *toArgIter++; - auto *load = - builder.createLoad(loc, toArg, LoadOwnershipQualifier::Unqualified); + auto toArg = *toArgIter++; + auto load = builder.emitLoadBorrowOperation(loc, toArg); + if (isa(load)) + valuesToCleanup.push_back(load); arguments.push_back(load); } + auto *fnArg = thunk->getArgumentsWithoutIndirectResults().back(); auto *apply = builder.createApply(loc, fnArg, SubstitutionMap(), arguments, /*isNonThrowing*/ false); @@ -413,8 +472,8 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, // Load direct results from indirect results. if (fromRes.isFormalIndirect()) { auto indRes = *fromIndResultsIter++; - auto *load = - builder.createLoad(loc, indRes, LoadOwnershipQualifier::Unqualified); + auto load = builder.emitLoadValueOperation(loc, indRes, + LoadOwnershipQualifier::Take); results.push_back(load); continue; } @@ -426,11 +485,28 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, assert(resultTy.isAddress()); #endif auto indRes = *toIndResultsIter++; - builder.createStore(loc, *fromDirResultsIter++, indRes, - StoreOwnershipQualifier::Unqualified); + auto dirRes = *fromDirResultsIter++; + builder.emitStoreValueOperation(loc, dirRes, indRes, + StoreOwnershipQualifier::Init); } auto retVal = joinElements(results, builder, loc); + // Clean up local values. + // Guaranteed values need an `end_borrow`. + // Owned values need to be destroyed. + for (auto arg : valuesToCleanup) { + switch (arg.getOwnershipKind()) { + case ValueOwnershipKind::Guaranteed: + builder.emitEndBorrowOperation(loc, arg); + break; + case ValueOwnershipKind::Owned: + case ValueOwnershipKind::Unowned: + case ValueOwnershipKind::None: + builder.emitDestroyOperation(loc, arg); + break; + } + } + // Deallocate local allocations. for (auto *alloc : llvm::reverse(localAllocations)) builder.createDeallocStack(loc, alloc); @@ -549,11 +625,11 @@ getOrCreateSubsetParametersThunkForLinearMap( auto *buf = builder.createAllocStack(loc, zeroSILObjType); localAllocations.push_back(buf); emitZeroIntoBuffer(builder, zeroType, buf, loc); - if (zeroSILType.isAddress()) + if (zeroSILType.isAddress()) { arguments.push_back(buf); - else { - auto *arg = - builder.createLoad(loc, buf, LoadOwnershipQualifier::Unqualified); + } else { + auto arg = builder.emitLoadValueOperation(loc, buf, + LoadOwnershipQualifier::Take); arguments.push_back(arg); } break; @@ -810,8 +886,6 @@ getOrCreateSubsetParametersThunkForDerivativeFunction( if (!thunk->empty()) return {thunk, interfaceSubs}; - // TODO(TF-1206): Enable ownership in all differentiation thunks. - thunk->setOwnershipEliminated(); thunk->setGenericEnvironment(genericEnv); auto *entry = thunk->createBasicBlock(); SILBuilder builder(entry); From 0ceaa5899c2f91a60e86b4c7cab86446f2b0c6a9 Mon Sep 17 00:00:00 2001 From: Alex Efremov <29282858+efremale@users.noreply.github.com> Date: Wed, 9 Sep 2020 03:15:48 +0200 Subject: [PATCH 627/663] [AutoDiff] Fix forward-mode crashes related to tangent buffers (#33633) Fixes foward-mode crashed related to: - Missing tangent buffers for non-wrt `inout` parameters. - Tangent buffers not being initialized due to the corresponding original buffer intialization instructions being non-active. - Non-varied indirect results not being initialized. - `emitDestroyValue` crashes due to `TangentVector` value category mismatch. Resolves TF-984 and SR-13447. Co-authored-by: Dan Zheng --- .../Differentiation/JVPCloner.cpp | 195 +++++++++++++----- .../Differentiation/LinearMapInfo.cpp | 3 +- .../forward_mode_diagnostics.swift | 18 +- .../validation-test/forward_mode.swift | 70 +++++++ 4 files changed, 225 insertions(+), 61 deletions(-) diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index 2586e5ac6ad2e..86c587e9bc47b 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -134,19 +134,6 @@ class JVPCloner::Implementation final // General utilities //--------------------------------------------------------------------------// - SILBasicBlock::iterator getNextDifferentialLocalAllocationInsertionPoint() { - // If there are no local allocations, insert at the beginning of the tangent - // entry. - if (differentialLocalAllocations.empty()) - return getDifferential().getEntryBlock()->begin(); - // Otherwise, insert before the last local allocation. Inserting before - // rather than after ensures that allocation and zero initialization - // instructions are grouped together. - auto lastLocalAlloc = differentialLocalAllocations.back(); - auto it = lastLocalAlloc->getDefiningInstruction()->getIterator(); - return it; - } - /// Get the lowered SIL type of the given AST type. SILType getLoweredType(Type type) { auto jvpGenSig = jvp->getLoweredFunctionType()->getSubstGenericSignature(); @@ -309,6 +296,8 @@ class JVPCloner::Implementation final // Tangent buffer mapping //--------------------------------------------------------------------------// + /// Sets the tangent buffer for the original buffer. Asserts that the + /// original buffer does not already have a tangent buffer. void setTangentBuffer(SILBasicBlock *origBB, SILValue originalBuffer, SILValue tangentBuffer) { assert(originalBuffer->getType().isAddress()); @@ -318,13 +307,14 @@ class JVPCloner::Implementation final (void)insertion; } + /// Returns the tangent buffer for the original buffer. Asserts that the + /// original buffer has a tangent buffer. SILValue &getTangentBuffer(SILBasicBlock *origBB, SILValue originalBuffer) { assert(originalBuffer->getType().isAddress()); assert(originalBuffer->getFunction() == original); - auto insertion = - bufferMap.try_emplace({origBB, originalBuffer}, SILValue()); - assert(!insertion.second && "Tangent buffer should already exist"); - return insertion.first->getSecond(); + auto it = bufferMap.find({origBB, originalBuffer}); + assert(it != bufferMap.end() && "Tangent buffer should already exist"); + return it->getSecond(); } //--------------------------------------------------------------------------// @@ -446,9 +436,21 @@ class JVPCloner::Implementation final // If an `apply` has active results or active inout parameters, replace it // with an `apply` of its JVP. void visitApplyInst(ApplyInst *ai) { + bool shouldDifferentiate = + differentialInfo.shouldDifferentiateApplySite(ai); + // If the function has no active arguments or results, zero-initialize the + // tangent buffers of the active indirect results. + if (!shouldDifferentiate) { + for (auto indResult : ai->getIndirectSILResults()) + if (activityInfo.isActive(indResult, getIndices())) { + auto &tanBuf = getTangentBuffer(ai->getParent(), indResult); + emitZeroIndirect(tanBuf->getType().getASTType(), tanBuf, + tanBuf.getLoc()); + } + } // If the function should not be differentiated or its the array literal // initialization intrinsic, just do standard cloning. - if (!differentialInfo.shouldDifferentiateApplySite(ai) || + if (!shouldDifferentiate || ArraySemanticsCall(ai, semantics::ARRAY_UNINITIALIZED_INTRINSIC)) { LLVM_DEBUG(getADDebugStream() << "No active results:\n" << *ai << '\n'); TypeSubstCloner::visitApplyInst(ai); @@ -789,7 +791,7 @@ class JVPCloner::Implementation final auto &diffBuilder = getDifferentialBuilder(); auto loc = dvi->getLoc(); auto tanVal = materializeTangent(getTangentValue(dvi->getOperand()), loc); - diffBuilder.emitDestroyValue(loc, tanVal); + diffBuilder.emitDestroyValueOperation(loc, tanVal); } CLONE_AND_EMIT_TANGENT(CopyValue, cvi) { @@ -804,7 +806,20 @@ class JVPCloner::Implementation final /// Handle `load` instruction. /// Original: y = load x /// Tangent: tan[y] = load tan[x] - CLONE_AND_EMIT_TANGENT(Load, li) { + void visitLoadInst(LoadInst *li) { + TypeSubstCloner::visitLoadInst(li); + // If an active buffer is loaded with take to a non-active value, destroy + // the active buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(li)) { + auto isTake = + (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take); + if (isTake && activityInfo.isActive(li->getOperand(), getIndices())) { + auto &tanBuf = getTangentBuffer(li->getParent(), li->getOperand()); + getDifferentialBuilder().emitDestroyOperation(tanBuf.getLoc(), tanBuf); + } + return; + } + // Otherwise, do standard differential cloning. auto &diffBuilder = getDifferentialBuilder(); auto *bb = li->getParent(); auto loc = li->getLoc(); @@ -829,7 +844,19 @@ class JVPCloner::Implementation final /// Handle `store` instruction in the differential. /// Original: store x to y /// Tangent: store tan[x] to tan[y] - CLONE_AND_EMIT_TANGENT(Store, si) { + void visitStoreInst(StoreInst *si) { + TypeSubstCloner::visitStoreInst(si); + // If a non-active value is stored into an active buffer, zero-initialize + // the active buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(si)) { + if (activityInfo.isActive(si->getDest(), getIndices())) { + auto &tanBufDest = getTangentBuffer(si->getParent(), si->getDest()); + emitZeroIndirect(tanBufDest->getType().getASTType(), tanBufDest, + tanBufDest.getLoc()); + } + return; + } + // Otherwise, do standard differential cloning. auto &diffBuilder = getDifferentialBuilder(); auto loc = si->getLoc(); auto tanValSrc = materializeTangent(getTangentValue(si->getSrc()), loc); @@ -841,7 +868,19 @@ class JVPCloner::Implementation final /// Handle `store_borrow` instruction in the differential. /// Original: store_borrow x to y /// Tangent: store_borrow tan[x] to tan[y] - CLONE_AND_EMIT_TANGENT(StoreBorrow, sbi) { + void visitStoreBorrowInst(StoreBorrowInst *sbi) { + TypeSubstCloner::visitStoreBorrowInst(sbi); + // If a non-active value is stored into an active buffer, zero-initialize + // the active buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(sbi)) { + if (activityInfo.isActive(sbi->getDest(), getIndices())) { + auto &tanBufDest = getTangentBuffer(sbi->getParent(), sbi->getDest()); + emitZeroIndirect(tanBufDest->getType().getASTType(), tanBufDest, + tanBufDest.getLoc()); + } + return; + } + // Otherwise, do standard differential cloning. auto &diffBuilder = getDifferentialBuilder(); auto loc = sbi->getLoc(); auto tanValSrc = materializeTangent(getTangentValue(sbi->getSrc()), loc); @@ -852,13 +891,32 @@ class JVPCloner::Implementation final /// Handle `copy_addr` instruction. /// Original: copy_addr x to y /// Tangent: copy_addr tan[x] to tan[y] - CLONE_AND_EMIT_TANGENT(CopyAddr, cai) { + void visitCopyAddrInst(CopyAddrInst *cai) { + TypeSubstCloner::visitCopyAddrInst(cai); + // If a non-active buffer is copied into an active buffer, zero-initialize + // the destination buffer's tangent buffer. + // If an active buffer is copied with take into a non-active buffer, destroy + // the source buffer's tangent buffer. + if (!differentialInfo.shouldDifferentiateInstruction(cai)) { + if (activityInfo.isActive(cai->getDest(), getIndices())) { + auto &tanBufDest = getTangentBuffer(cai->getParent(), cai->getDest()); + emitZeroIndirect(tanBufDest->getType().getASTType(), tanBufDest, + tanBufDest.getLoc()); + } + if (cai->isTakeOfSrc() && + activityInfo.isActive(cai->getSrc(), getIndices())) { + auto &tanBufSrc = getTangentBuffer(cai->getParent(), cai->getSrc()); + getDifferentialBuilder().emitDestroyOperation(tanBufSrc.getLoc(), + tanBufSrc); + } + return; + } + // Otherwise, do standard differential cloning. auto diffBuilder = getDifferentialBuilder(); auto loc = cai->getLoc(); auto *bb = cai->getParent(); auto &tanSrc = getTangentBuffer(bb, cai->getSrc()); auto tanDest = getTangentBuffer(bb, cai->getDest()); - diffBuilder.createCopyAddr(loc, tanSrc, tanDest, cai->isTakeOfSrc(), cai->isInitializationOfDest()); } @@ -918,8 +976,8 @@ class JVPCloner::Implementation final auto &diffBuilder = getDifferentialBuilder(); auto *bb = eai->getParent(); auto loc = eai->getLoc(); - auto tanSrc = getTangentBuffer(bb, eai->getOperand()); - diffBuilder.createEndAccess(loc, tanSrc, eai->isAborting()); + auto tanOperand = getTangentBuffer(bb, eai->getOperand()); + diffBuilder.createEndAccess(loc, tanOperand, eai->isAborting()); } /// Handle `alloc_stack` instruction. @@ -930,7 +988,7 @@ class JVPCloner::Implementation final auto *mappedAllocStackInst = diffBuilder.createAllocStack( asi->getLoc(), getRemappedTangentType(asi->getElementType()), asi->getVarInfo()); - bufferMap.try_emplace({asi->getParent(), asi}, mappedAllocStackInst); + setTangentBuffer(asi->getParent(), asi, mappedAllocStackInst); } /// Handle `dealloc_stack` instruction. @@ -1062,16 +1120,15 @@ class JVPCloner::Implementation final auto tanType = getRemappedTangentType(tei->getType()); auto tanSource = materializeTangent(getTangentValue(tei->getOperand()), loc); - SILValue tanBuf; - // If the tangent buffer of the source does not have a tuple type, then + // If the tangent value of the source does not have a tuple type, then // it must represent a "single element tuple type". Use it directly. if (!tanSource->getType().is()) { setTangentValue(tei->getParent(), tei, makeConcreteTangentValue(tanSource)); } else { - tanBuf = + auto tanElt = diffBuilder.createTupleExtract(loc, tanSource, tanIndex, tanType); - bufferMap.try_emplace({tei->getParent(), tei}, tanBuf); + setTangentValue(tei->getParent(), tei, makeConcreteTangentValue(tanElt)); } } @@ -1100,7 +1157,7 @@ class JVPCloner::Implementation final tanBuf = diffBuilder.createTupleElementAddr(teai->getLoc(), tanSource, tanIndex, tanType); } - bufferMap.try_emplace({teai->getParent(), teai}, tanBuf); + setTangentBuffer(teai->getParent(), teai, tanBuf); } /// Handle `destructure_tuple` instruction. @@ -1282,9 +1339,8 @@ class JVPCloner::Implementation final // Collect original results. SmallVector originalResults; collectAllDirectResultsInTypeOrder(*original, originalResults); - // Collect differential return elements. + // Collect differential direct results. SmallVector retElts; - // for (auto origResult : originalResults) { for (auto i : range(originalResults.size())) { auto origResult = originalResults[i]; if (!getIndices().results->contains(i)) @@ -1401,7 +1457,10 @@ JVPCloner::Implementation::getDifferentialStructElement(SILBasicBlock *origBB, void JVPCloner::Implementation::prepareForDifferentialGeneration() { // Create differential blocks and arguments. auto &differential = getDifferential(); + auto diffLoc = differential.getLocation(); auto *origEntry = original->getEntryBlock(); + auto origFnTy = original->getLoweredFunctionType(); + for (auto &origBB : *original) { auto *diffBB = differential.createBasicBlock(); diffBBMap.insert({&origBB, diffBB}); @@ -1482,21 +1541,51 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { << " as the tangent of original result " << *origArg); } - // Initialize tangent mapping for indirect results. - auto origIndResults = original->getIndirectResults(); + // Initialize tangent mapping for original indirect results and non-wrt + // `inout` parameters. The tangent buffers of these address values are + // differential indirect results. + + // Collect original results. + SmallVector originalResults; + collectAllFormalResultsInTypeOrder(*original, originalResults); + + // Iterate over differentiability results. + differentialBuilder.setInsertionPoint(differential.getEntryBlock()); auto diffIndResults = differential.getIndirectResults(); -#ifndef NDEBUG - unsigned numNonWrtInoutParameters = llvm::count_if( - range(original->getLoweredFunctionType()->getNumParameters()), - [&] (unsigned i) { - auto ¶mInfo = original->getLoweredFunctionType()->getParameters()[i]; - return paramInfo.isIndirectInOut() && !getIndices().parameters->contains(i); - }); -#endif - assert(origIndResults.size() + numNonWrtInoutParameters == diffIndResults.size()); - for (auto &origBB : *original) - for (auto i : indices(origIndResults)) - setTangentBuffer(&origBB, origIndResults[i], diffIndResults[i]); + unsigned differentialIndirectResultIndex = 0; + for (auto resultIndex : getIndices().results->getIndices()) { + auto origResult = originalResults[resultIndex]; + // Handle original formal indirect result. + if (resultIndex < origFnTy->getNumResults()) { + // Skip original direct results. + if (origResult->getType().isObject()) + continue; + auto diffIndResult = diffIndResults[differentialIndirectResultIndex++]; + setTangentBuffer(origEntry, origResult, diffIndResult); + // If original indirect result is non-varied, zero-initialize its tangent + // buffer. + if (!activityInfo.isVaried(origResult, getIndices().parameters)) + emitZeroIndirect(diffIndResult->getType().getASTType(), + diffIndResult, diffLoc); + continue; + } + // Handle original non-wrt `inout` parameter. + // Only original *non-wrt* `inout` parameters have corresponding + // differential indirect results. + auto inoutParamIndex = resultIndex - origFnTy->getNumResults(); + auto inoutParamIt = std::next( + origFnTy->getIndirectMutatingParameters().begin(), inoutParamIndex); + auto paramIndex = + std::distance(origFnTy->getParameters().begin(), &*inoutParamIt); + if (getIndices().parameters->contains(paramIndex)) + continue; + auto diffIndResult = diffIndResults[differentialIndirectResultIndex++]; + setTangentBuffer(origEntry, origResult, diffIndResult); + // Original `inout` parameters are initialized, so their tangent buffers + // must also be initialized. + emitZeroIndirect(diffIndResult->getType().getASTType(), + diffIndResult, diffLoc); + } } /*static*/ SILFunction *JVPCloner::Implementation::createEmptyDifferential( @@ -1526,7 +1615,6 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto origParams = origTy->getParameters(); auto indices = witness->getSILAutoDiffIndices(); - for (auto resultIndex : indices.results->getIndices()) { if (resultIndex < origTy->getNumResults()) { // Handle formal original result. @@ -1539,17 +1627,16 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { ->getType() ->getCanonicalType(witnessCanGenSig), origResult.getConvention())); - } - else { + } else { // Handle original `inout` parameter. auto inoutParamIndex = resultIndex - origTy->getNumResults(); auto inoutParamIt = std::next( origTy->getIndirectMutatingParameters().begin(), inoutParamIndex); auto paramIndex = std::distance(origTy->getParameters().begin(), &*inoutParamIt); - // If the original `inout` parameter is a differentiability parameter, then - // it already has a corresponding differential parameter. Skip adding a - // corresponding differential result. + // If the original `inout` parameter is a differentiability parameter, + // then it already has a corresponding differential parameter. Do not add + // a corresponding differential result. if (indices.parameters->contains(paramIndex)) continue; auto inoutParam = origTy->getParameters()[paramIndex]; diff --git a/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp b/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp index e27b7f38a1a3b..8fe0323a91315 100644 --- a/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp +++ b/lib/SILOptimizer/Differentiation/LinearMapInfo.cpp @@ -455,7 +455,8 @@ void LinearMapInfo::generateDifferentiationDataStructures( /// 3. The instruction has both an active result (direct or indirect) and an /// active argument. bool LinearMapInfo::shouldDifferentiateApplySite(FullApplySite applySite) { - // Function applications with an inout argument should be differentiated. + // Function applications with an active inout argument should be + // differentiated. for (auto inoutArg : applySite.getInoutArguments()) if (activityInfo.isActive(inoutArg, indices)) return true; diff --git a/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift b/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift index ad21c18467142..3abe2229ea33f 100644 --- a/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift @@ -6,6 +6,7 @@ // forward mode reaches feature parity with reverse mode. import _Differentiation +import DifferentiationUnittest //===----------------------------------------------------------------------===// // Basic function @@ -85,10 +86,8 @@ func activeInoutParamControlFlow(_ array: [Float]) -> Float { return result } -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* struct X: Differentiable { - var x : Float + var x: Float @differentiable(wrt: y) mutating func mutate(_ y: X) { self.x = y.x } @@ -101,7 +100,6 @@ func activeMutatingMethod(_ x: Float) -> Float { x2.mutate(x1) return x1.x } -*/ struct Mut: Differentiable {} @@ -240,12 +238,16 @@ final class ClassTangentPropertyWrongType: Differentiable { func move(along direction: TangentVector) {} } -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. +// SR-13464: Missing support for classes in forward-mode AD /* +// xpected-error @+2 {{function is not differentiable}} +// xpected-note @+3 {{when differentiating this function definition}} @differentiable @_silgen_name("test_class_tangent_property_wrong_type") func testClassTangentPropertyWrongType(_ c: ClassTangentPropertyWrongType) -> Float { + // xpected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = c + // xpected-note @+1 {{cannot differentiate access to property 'ClassTangentPropertyWrongType.x' because 'ClassTangentPropertyWrongType.TangentVector.x' does not have expected type 'Float.TangentVector' (aka 'Float')}} return tmp.x } */ @@ -285,12 +287,16 @@ final class ClassTangentPropertyNotStored: Differentiable { func move(along direction: TangentVector) {} } -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. +// SR-13464: Missing support for classes in forward-mode AD /* +// xpected-error @+2 {{function is not differentiable}} +// xpected-note @+3 {{when differentiating this function definition}} @differentiable @_silgen_name("test_class_tangent_property_not_stored") func testClassTangentPropertyNotStored(_ c: ClassTangentPropertyNotStored) -> Float { + // xpected-warning @+1 {{variable 'tmp' was never mutated}} var tmp = c + // xpected-note @+1 {{cannot differentiate access to property 'ClassTangentPropertyNotStored.x' because 'ClassTangentPropertyNotStored.TangentVector.x' is not a stored property}} return tmp.x } */ diff --git a/test/AutoDiff/validation-test/forward_mode.swift b/test/AutoDiff/validation-test/forward_mode.swift index c29b87f34c198..906d9dedbee23 100644 --- a/test/AutoDiff/validation-test/forward_mode.swift +++ b/test/AutoDiff/validation-test/forward_mode.swift @@ -1319,6 +1319,76 @@ ForwardModeTests.test("ForceUnwrapping") { expectEqual(5, forceUnwrap(Float(2))) } +ForwardModeTests.test("NonVariedResult") { + @differentiable(wrt: x) + func nonWrtInoutParam(_ x: T, _ y: inout T) { + y = x + } + + @differentiable + func wrtInoutParam(_ x: T, _ y: inout T) { + y = x + } + + @differentiable(wrt: x) + func nonWrtInoutParamNonVaried(_ x: T, _ y: inout T) {} + + @differentiable(wrt: x) + func wrtInoutParamNonVaried(_ x: T, _ y: inout T) {} + + @differentiable + func variedResultTracked(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + nonWrtInoutParam(x, &result) + return result + } + + @differentiable + func variedResultTracked2(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + wrtInoutParam(x, &result) + return result + } + + @differentiable + func nonVariedResultTracked(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + nonWrtInoutParamNonVaried(x, &result) + return result + } + + @differentiable + func nonVariedResultTracked2(_ x: Tracked) -> Tracked { + // expected-warning @+1 {{variable 'result' was never mutated}} + var result: Tracked = 0 + return result + } + + @differentiable + func nonVariedResultTracked3(_ x: Tracked) -> Tracked { + return 0 + } + + @differentiable + func nonVariedResultTracked4(_ x: Tracked) -> Tracked { + var result: Tracked = 0 + wrtInoutParamNonVaried(x, &result) + return result + } +} + +ForwardModeTests.test("ApplyNonActiveIndirectResult") { + func identity(_ x: T) -> T { x } + + @differentiable + func applyNonactiveArgumentActiveIndirectResult(_ x: Tracked) -> Tracked { + var y = identity(0 as Tracked) + y = x + return y + } + expectEqual(1.0, derivative(at: 2, in: applyNonactiveArgumentActiveIndirectResult)) +} + //===----------------------------------------------------------------------===// // Array methods from ArrayDifferentiation.swift //===----------------------------------------------------------------------===// From 5bce81306f8773c556fa44c702f4196c19ff8d9c Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 12 Sep 2020 20:40:51 +0900 Subject: [PATCH 628/663] [WASM] Fix lazy global initializer signature Lazy global init is used with swift_once which passes a context pointer parameter. If lazy global init doesn't take a context argument, caller and callee signatures are mismatched and it causes runtime exception on WebAssembly runtime. So we need to add dummy argument to consume the context pointer. See also: emitLazyGlobalInitializer --- lib/SILGen/SILGen.cpp | 14 +++++++++++++- lib/SILGen/SILGenGlobalVariable.cpp | 13 +++++++++++++ stdlib/public/runtime/Once.cpp | 7 +------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 4943330220262..1eeb2d26095e4 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1399,7 +1399,19 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, cast(getBuiltinValueDecl(C, C.getIdentifier("once"))); auto blockParam = onceBuiltin->getParameters()->get(1); auto *type = blockParam->getType()->castTo(); - Type initType = FunctionType::get({}, TupleType::getEmpty(C), + SmallVector params; + // wasm: Lazy global init is used with swift_once which passes a context + // pointer parameter. If lazy global init doesn't take a context argument, + // caller and callee signatures are mismatched and it causes runtime + // exception on WebAssembly runtime. So we need to add dummy argument + // to consume the context pointer. + // See also: emitLazyGlobalInitializer + if (C.LangOpts.Target.isOSBinFormatWasm()) { + auto dummyParam = AnyFunctionType::Param(C.getUnsafeRawPointerDecl()->getDeclaredInterfaceType() + ->getCanonicalType()); + params.push_back(dummyParam); + } + Type initType = FunctionType::get(params, TupleType::getEmpty(C), type->getExtInfo()); auto initSILType = cast( Types.getLoweredRValueType(TypeExpansionContext::minimal(), initType)); diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index a43ce63f99508..eaaea20ea981d 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -212,6 +212,19 @@ void SILGenFunction::emitLazyGlobalInitializer(PatternBindingDecl *binding, unsigned pbdEntry) { MagicFunctionName = SILGenModule::getMagicFunctionName(binding->getDeclContext()); + ASTContext &C = getASTContext(); + // wasm: Lazy global init is used with swift_once which passes a context + // pointer parameter. If lazy global init doesn't take a context argument, + // caller and callee signatures are mismatched and it causes runtime + // exception on WebAssembly runtime. So we need to add dummy argument + // to consume the context pointer. + // See also: emitLazyGlobalInitializer + if (C.LangOpts.Target.isOSBinFormatWasm()) { + auto UnsafeRawPointer = C.getUnsafeRawPointerDecl(); + auto UnsafeRawPtrTy = getLoweredType(UnsafeRawPointer->getDeclaredInterfaceType()); + F.front().createFunctionArgument(UnsafeRawPtrTy); + } + { Scope scope(Cleanups, binding); diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index c3752d4b171b5..1460b0603ef17 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -55,12 +55,7 @@ void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), #ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME if (! *predicate) { *predicate = true; - // WebAssembly: hack: Swift compiler passes in a fn that doesn't take a parameter, - // which is invalid in WebAssembly. So swift_once casts the function. - // The correct way to fix this is to change - // SILGenModule::emitLazyGlobalInitializer - // but this is OK as a proof of concept. - ((void (*)())fn)(); + fn(context); } #elif defined(__APPLE__) dispatch_once_f(predicate, context, fn); From 482b33abf687e61590f34292bd2a67a8956754ab Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 12 Sep 2020 23:59:43 +0900 Subject: [PATCH 629/663] [WASM] Always build lld when building for wasm Because compiler emits object file using latest LLVM but wasm-ld in wasi-sdk is older. This version difference causes incompatible relocation type error. After upgrade lld, --no-thread is replaced with --threads=1 --- utils/build-script-impl | 3 ++- utils/webassembly/static-executable-args.lnk | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 073f2b37afa8d..03c5c788e54f9 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1622,7 +1622,8 @@ for host in "${ALL_HOSTS[@]}"; do # # This makes it easier to build target stdlibs on systems that # have old toolchains without more modern linker features. - if [[ "$(uname -s)" != "Darwin" ]] ; then + # wasm: lld should be built when cross building for wasm + if [[ "$(uname -s)" != "Darwin" || ! "${SKIP_BUILD_WASM}" ]] ; then if [[ ! "${SKIP_BUILD_LLD}" ]]; then llvm_enable_projects+=("lld") fi diff --git a/utils/webassembly/static-executable-args.lnk b/utils/webassembly/static-executable-args.lnk index 2d8c872154c5f..ec481f273908c 100644 --- a/utils/webassembly/static-executable-args.lnk +++ b/utils/webassembly/static-executable-args.lnk @@ -11,5 +11,5 @@ -lwasi-emulated-mman -Xlinker --error-limit=0 -Xlinker --no-gc-sections --Xlinker --no-threads +-Xlinker --threads=1 -D_WASI_EMULATED_MMAN From 6375885b34892cc769c3d050d9dfa7b53e25bec3 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 13 Sep 2020 00:02:35 +0900 Subject: [PATCH 630/663] [WASM] Cross build compiler-rt for WebAssembly --- utils/build-presets.ini | 2 ++ utils/build-script-impl | 9 +++++++++ utils/webassembly/compiler-rt-cache.cmake | 14 ++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 utils/webassembly/compiler-rt-cache.cmake diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 948dc027489fd..cdd03b1f80dbd 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2646,6 +2646,7 @@ extra-cmake-options= -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE -DCMAKE_AR="%(SOURCE_PATH)s/wasi-sdk/bin/llvm-ar" -DCMAKE_RANLIB="%(SOURCE_PATH)s/wasi-sdk/bin/llvm-ranlib" + -DCLANG_COMPILER_RT_CMAKE_ARGS='-DCMAKE_TOOLCHAIN_FILE=%(SOURCE_PATH)s/swift/utils/webassembly/compiler-rt-cache.cmake' -DSWIFTWASM_DISABLE_REFLECTION_TEST=TRUE [preset: webassembly-macos-target] @@ -2664,4 +2665,5 @@ extra-cmake-options= -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE -DCMAKE_AR='/usr/local/opt/llvm/bin/llvm-ar' -DCMAKE_RANLIB='/usr/local/opt/llvm/bin/llvm-ranlib' + -DCLANG_COMPILER_RT_CMAKE_ARGS='-DCMAKE_TOOLCHAIN_FILE=%(SOURCE_PATH)s/swift/utils/webassembly/compiler-rt-cache.cmake' -DSWIFTWASM_DISABLE_REFLECTION_TEST=TRUE diff --git a/utils/build-script-impl b/utils/build-script-impl index 03c5c788e54f9..99f0daf80c3a3 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1629,6 +1629,15 @@ for host in "${ALL_HOSTS[@]}"; do fi fi + # wasm: SWIFT_WASI_SDK_PATH is used to determine wasi-sysroot + # to build compiler-rt for wasm32-wasi + if [[ ! "${SKIP_BUILD_WASM}" ]]; then + cmake_options=( + "${cmake_options[@]}" + -DCOMPILER_RT_SWIFT_WASI_SDK_PATH:STRING="${WASI_SDK}" + ) + fi + cmake_options+=( -DLLVM_ENABLE_PROJECTS="$(join ";" ${llvm_enable_projects[@]})" ) diff --git a/utils/webassembly/compiler-rt-cache.cmake b/utils/webassembly/compiler-rt-cache.cmake new file mode 100644 index 0000000000000..ef35520e839c6 --- /dev/null +++ b/utils/webassembly/compiler-rt-cache.cmake @@ -0,0 +1,14 @@ +set(COMPILER_RT_DEFAULT_TARGET_ARCH wasm32 CACHE STRING "" FORCE) +set(COMPILER_RT_DEFAULT_TARGET_ONLY TRUE CACHE BOOL "" FORCE) +set(CMAKE_C_COMPILER_TARGET wasm32-wasi CACHE STRING "" FORCE) +set(CMAKE_C_COMPILER_FORCED TRUE CACHE BOOL "") +set(CMAKE_CXX_COMPILER_FORCED TRUE CACHE BOOL "") +set(CMAKE_SYSTEM_NAME Wasm) +set(CMAKE_SYSROOT ${COMPILER_RT_SWIFT_WASI_SDK_PATH}/share/wasi-sysroot CACHE STRING "") +set(CMAKE_SIZEOF_VOID_P 4 CACHE STRING "") +set(COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "") +set(COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "") +set(COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "") +set(COMPILER_RT_HAS_FPIC_FLAG OFF CACHE BOOL "") +set(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN OFF CACHE BOOL "") +set(COMPILER_RT_OS_DIR wasi CACHE STRING "") From b6bcd01b49f024aa0a4285dd6bfea40839033b6c Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 13 Sep 2020 00:15:35 +0900 Subject: [PATCH 631/663] [WASM] Use llvm build directory binary --- test/lit.cfg | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/lit.cfg b/test/lit.cfg index 470545e06e829..39b7b7cca9dfa 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1372,8 +1372,6 @@ elif run_os == 'linux-androideabi' or run_os == 'linux-android': # The Swift interpreter is not available when targeting Android. config.available_features.discard('swift_interpreter') elif run_os == 'wasi': - tools_directory = pipes.quote(make_path(config.wasi_sdk_path, "bin")) - lit_config.note("Testing WebAssembly/WASI " + config.variant_triple) config.target_object_format = "wasm" @@ -1409,7 +1407,6 @@ elif run_os == 'wasi': '-target', config.variant_triple, '-Xcc', '--sysroot=%s' % config.variant_sdk, '-Xclang-linker', '--sysroot=%s' % config.variant_sdk, - '-tools-directory', tools_directory, '-toolchain-stdlib-rpath', resource_dir_opt, mcp_opt, config.swift_test_options, config.swift_driver_test_options, swift_execution_tests_extra_flags]) @@ -1422,7 +1419,6 @@ elif run_os == 'wasi': config.swift_frontend, '-target', config.variant_triple, '-Xcc', '--sysroot=%s' % config.variant_sdk, - '-tools-directory', tools_directory, resource_dir_opt, mcp_opt, config.swift_test_options, config.swift_frontend_test_options]) subst_target_swift_frontend_mock_sdk = config.target_swift_frontend From 1248374fdc3324d17c48f7b0373447ab7d8a32aa Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 13 Sep 2020 01:57:47 +0900 Subject: [PATCH 632/663] [WASM] Install self built llvm components --- utils/build-presets.ini | 2 +- utils/webassembly/build-toolchain.sh | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index cdd03b1f80dbd..25090c6356dad 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2578,7 +2578,7 @@ skip-build-benchmarks llvm-targets-to-build=X86;AArch64;WebAssembly install-destdir=%(INSTALL_DESTDIR)s swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;sdk-overlay;parser-lib;editor-integration;tools;testsuite-tools;toolchain-tools;license;sourcekit-inproc;swift-remote-mirror;swift-remote-mirror-headers;clang-resource-dir-symlink -llvm-install-components=clang +llvm-install-components=clang;compiler-rt;lld install-swift install-prefix=/%(TOOLCHAIN_NAME)s/usr swift-darwin-supported-archs=x86_64 diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 72f246b487201..3ffa97dc723fa 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -68,8 +68,6 @@ $SOURCE_PATH/swift/utils/build-script \ C_CXX_LAUNCHER="$(which sccache)" # Merge wasi-sdk and the toolchain -cp -a $WASI_SDK_PATH/lib/clang $HOST_TOOLCHAIN_SDK/usr/lib -cp -a $WASI_SDK_PATH/bin/{*ld,llvm-ar} $HOST_TOOLCHAIN_SDK/usr/bin cp -r $WASI_SDK_PATH/share/wasi-sysroot $HOST_TOOLCHAIN_SDK/usr/share # Replace absolute sysroot path with relative path From eb8b336cf7abf1c9a90c16f1a99487c4c67c0f64 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 13 Sep 2020 10:01:06 +0900 Subject: [PATCH 633/663] [WASM] Install llvm components in building target toolchain --- utils/build-presets.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 25090c6356dad..225c266f296a7 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2594,7 +2594,6 @@ extra-cmake-options= llbuild swiftpm -install-llvm install-swift install-llbuild install-swiftpm @@ -2623,6 +2622,8 @@ skip-test-xctest mixin-preset=webassembly wasm verbose +# Install lld, compiler-rt and clang +install-llvm build-stdlib-deployment-targets=wasi-wasm32 build-swift-dynamic-sdk-overlay=false build-swift-dynamic-stdlib=false From e4dfff534bf544f06d48cd68e18883266bf7f6bd Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 14 Sep 2020 09:26:36 +0900 Subject: [PATCH 634/663] [WASM] Cleanup llvm build directory before building for wasm target --- utils/webassembly/build-toolchain.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 3ffa97dc723fa..5b7bf75463eac 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -54,6 +54,7 @@ $SOURCE_PATH/swift/utils/build-script \ # `build-script` invocation doesn't pick up wrong CMake config files. # For some reason passing `--reconfigure` to `build-script` won't do this. rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/swift-* +rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/llvm-* # build the cross-compilled toolchain $SOURCE_PATH/swift/utils/build-script \ From e06c8df6b9c2405525dcefe45857827d6ef8a732 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 16 Sep 2020 09:28:57 +0900 Subject: [PATCH 635/663] [WASM] Cleanup build directory --- utils/webassembly/build-toolchain.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 5b7bf75463eac..dd45226560476 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -83,5 +83,10 @@ rsync -v -a $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/lib/ $HOST_TOOLCHAIN_SDK/us $UTILS_PATH/build-foundation.sh $HOST_TOOLCHAIN_SDK $UTILS_PATH/build-xctest.sh $HOST_TOOLCHAIN_SDK +# Cleanup build directory on CI +if [[ -n "${CI}" ]]; then + rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/ +fi + cd $HOST_TOOLCHAIN_DESTDIR tar cfz $PACKAGE_ARTIFACT $TOOLCHAIN_NAME From 075a9eb50d61e357db2d47525d25386ff6bb1789 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 16 Sep 2020 14:45:02 +0900 Subject: [PATCH 636/663] [WASM] Install llvm tools in toolchain bin dir --- utils/build-presets.ini | 2 +- utils/webassembly/build-toolchain.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 225c266f296a7..c17ae111cca89 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2578,7 +2578,7 @@ skip-build-benchmarks llvm-targets-to-build=X86;AArch64;WebAssembly install-destdir=%(INSTALL_DESTDIR)s swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;sdk-overlay;parser-lib;editor-integration;tools;testsuite-tools;toolchain-tools;license;sourcekit-inproc;swift-remote-mirror;swift-remote-mirror-headers;clang-resource-dir-symlink -llvm-install-components=clang;compiler-rt;lld +llvm-install-components=clang;compiler-rt;lld;llvm-ar;llvm-ranlib install-swift install-prefix=/%(TOOLCHAIN_NAME)s/usr swift-darwin-supported-archs=x86_64 diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index dd45226560476..f3a9af8c625c0 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -79,6 +79,7 @@ sed -i -e "s@\".*/include@\"../../../../share/wasi-sysroot/include@g" $SOURCE_PA # Avoid copying usr/lib/swift/clang because our toolchain's one is a directory # but nightly's one is symbolic link. A simple copy fails to merge them. rsync -v -a $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/lib/ $HOST_TOOLCHAIN_SDK/usr/lib/ --exclude 'swift/clang' +rsync -v -a $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/bin/ $HOST_TOOLCHAIN_SDK/usr/bin/ $UTILS_PATH/build-foundation.sh $HOST_TOOLCHAIN_SDK $UTILS_PATH/build-xctest.sh $HOST_TOOLCHAIN_SDK From b53d7136c4e5d3d43b8fbea1273b1e5ee2d26d41 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 16 Sep 2020 18:30:16 +0900 Subject: [PATCH 637/663] [WASM] Keep build directory on macOS CI to run tests --- utils/webassembly/build-toolchain.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index f3a9af8c625c0..af376e5b39225 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -84,8 +84,8 @@ rsync -v -a $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/bin/ $HOST_TOOLCHAIN_SDK/us $UTILS_PATH/build-foundation.sh $HOST_TOOLCHAIN_SDK $UTILS_PATH/build-xctest.sh $HOST_TOOLCHAIN_SDK -# Cleanup build directory on CI -if [[ -n "${CI}" ]]; then +# Cleanup build directory on Linux CI +if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/ fi From 8573f1f41130d3dac07645d2ed141aa7df6675c2 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 16 Sep 2020 19:24:17 +0900 Subject: [PATCH 638/663] Trigger CI again From d6463fd3a414d6abdb5440a4bd1c6ccdffc14ec1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 16 Sep 2020 19:45:55 +0900 Subject: [PATCH 639/663] [WASM] Install six on macOS --- utils/webassembly/macos/install-dependencies.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/webassembly/macos/install-dependencies.sh b/utils/webassembly/macos/install-dependencies.sh index 8e715d101d874..fb57f205ce3ec 100755 --- a/utils/webassembly/macos/install-dependencies.sh +++ b/utils/webassembly/macos/install-dependencies.sh @@ -3,6 +3,7 @@ set -ex brew uninstall python@2 || true +sudo pip install six brew install cmake ninja llvm sccache wasmer SOURCE_PATH="$( cd "$(dirname $0)/../../../../" && pwd )" From dc91d077cc413dafad669c517a6e33878cf7dcfe Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 16 Sep 2020 19:55:29 +0900 Subject: [PATCH 640/663] [WASM] Uninstall python2 from macOS VM --- utils/webassembly/macos/install-dependencies.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/webassembly/macos/install-dependencies.sh b/utils/webassembly/macos/install-dependencies.sh index fb57f205ce3ec..59394716e1b5a 100755 --- a/utils/webassembly/macos/install-dependencies.sh +++ b/utils/webassembly/macos/install-dependencies.sh @@ -2,8 +2,7 @@ set -ex -brew uninstall python@2 || true -sudo pip install six +brew uninstall $(brew list | grep python@2) brew install cmake ninja llvm sccache wasmer SOURCE_PATH="$( cd "$(dirname $0)/../../../../" && pwd )" From 7b19834ab51ebb0df2bee19939789df87fb74863 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 16 Sep 2020 23:31:19 +0900 Subject: [PATCH 641/663] Cleanup only foundation and swiftpm build dir to run tests --- utils/webassembly/build-toolchain.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index af376e5b39225..1fe2d8acdae6a 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -86,7 +86,8 @@ $UTILS_PATH/build-xctest.sh $HOST_TOOLCHAIN_SDK # Cleanup build directory on Linux CI if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then - rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/ + rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/foundation-* + rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/swiftpm-* fi cd $HOST_TOOLCHAIN_DESTDIR From 9d8d2143f4ea6d81abd3823abe55d4256d6bdf10 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 00:17:39 +0900 Subject: [PATCH 642/663] [WASM] Disable test/stdlib/PrintStruct.swift temporarily --- test/stdlib/PrintStruct.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/stdlib/PrintStruct.swift b/test/stdlib/PrintStruct.swift index c637d5bebf01c..b616e61f5172a 100644 --- a/test/stdlib/PrintStruct.swift +++ b/test/stdlib/PrintStruct.swift @@ -4,6 +4,10 @@ // RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: executable_test +// +// FIXME Disable this case because this failed on only CI. +// Failed with 'Caught exception of type "CallIndirectOOB"' +// UNSUPPORTED: CPU=wasm32 import StdlibUnittest import PrintTestTypes From 29705bcb3f0ffdfc64f698fb581936cc9c2cb38e Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 08:23:00 +0900 Subject: [PATCH 643/663] Update cache mechanism --- .github/workflows/main.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d1903aed7e554..350ed97acddeb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,10 +28,18 @@ jobs: - uses: actions/checkout@v1 with: path: swift + - name: Prepare sccache timestamp + id: cache_timestamp + shell: cmake -P {0} + run: | + string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) + message("::set-output name=timestamp::${current_date}") - uses: actions/cache@v1 with: path: ../build-cache - key: ${{ runner.os }}-sccache-v9 + key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} + restore-keys: | + ${{ runner.os }}-v10- - name: Build Linux installable archive run: | ./utils/webassembly/ci.sh @@ -58,10 +66,18 @@ jobs: - uses: actions/checkout@v1 with: path: swift + - name: Prepare sccache timestamp + id: cache_timestamp + shell: cmake -P {0} + run: | + string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) + message("::set-output name=timestamp::${current_date}") - uses: actions/cache@v1 with: path: ../build-cache - key: ${{ runner.os }}-sccache-v9 + key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} + restore-keys: | + ${{ runner.os }}-v10- - name: Build macOS installable archive run: | sudo xcode-select --switch /Applications/Xcode_12_beta.app/Contents/Developer/ From 1e1150e608e5f7bd120d8917d5940b7d3b13c6cf Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 08:34:57 +0900 Subject: [PATCH 644/663] Reuse LLVM build dir and clear only compiler-rt dir --- utils/webassembly/build-toolchain.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 1fe2d8acdae6a..3646d26bef8ba 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -40,6 +40,8 @@ DISPLAY_NAME="${DISPLAY_NAME_SHORT} ${YEAR}-${MONTH}-${DAY}" HOST_TOOLCHAIN_DESTDIR=$SOURCE_PATH/host-toolchain-sdk HOST_TOOLCHAIN_SDK=$HOST_TOOLCHAIN_DESTDIR/$TOOLCHAIN_NAME +BUILD_DIR=$SOURCE_PATH/build/Ninja-ReleaseAssert + # Avoid clang headers symlink issues mkdir -p $HOST_TOOLCHAIN_SDK/usr/lib/clang/10.0.0 @@ -53,12 +55,13 @@ $SOURCE_PATH/swift/utils/build-script \ # Clean up the host toolchain build directory so that the next # `build-script` invocation doesn't pick up wrong CMake config files. # For some reason passing `--reconfigure` to `build-script` won't do this. -rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/swift-* -rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/llvm-* +rm -rf $BUILD_DIR/swift-* +# Clean up compiler-rt dir to cross compile it for host and wasm32 +(cd $BUILD_DIR/llvm-* && ninja compiler-rt-clear) # build the cross-compilled toolchain $SOURCE_PATH/swift/utils/build-script \ - --preset=$TARGET_PRESET \ + --preset=$TARGET_PRESET --reconfigure \ INSTALL_DESTDIR="$SOURCE_PATH/install" \ SOURCE_PATH="$SOURCE_PATH" \ BUNDLE_IDENTIFIER="${BUNDLE_IDENTIFIER}" \ @@ -86,8 +89,7 @@ $UTILS_PATH/build-xctest.sh $HOST_TOOLCHAIN_SDK # Cleanup build directory on Linux CI if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then - rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/foundation-* - rm -rf $SOURCE_PATH/build/Ninja-ReleaseAssert/swiftpm-* + rm -rf $BUILD_DIR/foundation-* $BUILD_DIR/swiftpm-* fi cd $HOST_TOOLCHAIN_DESTDIR From 1d3c8c8efa19b78d039ad627077e959fb97c6521 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 08:36:11 +0900 Subject: [PATCH 645/663] Create cache on Linux --- utils/webassembly/build-toolchain.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 3646d26bef8ba..7750feb17d157 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -52,6 +52,11 @@ $SOURCE_PATH/swift/utils/build-script \ TOOLCHAIN_NAME="$TOOLCHAIN_NAME" \ C_CXX_LAUNCHER="$(which sccache)" +if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then + echo "Exit to create a cache temporarily" + exit 0 +fi + # Clean up the host toolchain build directory so that the next # `build-script` invocation doesn't pick up wrong CMake config files. # For some reason passing `--reconfigure` to `build-script` won't do this. From 6a629b7d38393cf541bc9c3caa3d863bc04826ab Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 12:10:01 +0900 Subject: [PATCH 646/663] Create cache on Linux again --- utils/webassembly/ci.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/webassembly/ci.sh b/utils/webassembly/ci.sh index c3ffb2877bbdc..1a31e4520703a 100755 --- a/utils/webassembly/ci.sh +++ b/utils/webassembly/ci.sh @@ -24,6 +24,12 @@ export SCCACHE_DIR="$SOURCE_PATH/build-cache" $BUILD_SCRIPT + +if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then + echo "Exit to create a cache temporarily" + exit 0 +fi + if [[ "$(uname)" == "Darwin" ]]; then # workaround: host target test directory is necessary to use run-test mkdir -p $BUILD_DIR/swift-macosx-x86_64/test-macosx-x86_64 From 77b57834a19da1d3f32b6f787f6575c170993a32 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 12:22:28 +0900 Subject: [PATCH 647/663] Fix cache key --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 350ed97acddeb..3d9bf393e31ed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,7 +39,7 @@ jobs: path: ../build-cache key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} restore-keys: | - ${{ runner.os }}-v10- + ${{ runner.os }}-sccache-v10- - name: Build Linux installable archive run: | ./utils/webassembly/ci.sh @@ -77,7 +77,7 @@ jobs: path: ../build-cache key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} restore-keys: | - ${{ runner.os }}-v10- + ${{ runner.os }}-sccache-v10- - name: Build macOS installable archive run: | sudo xcode-select --switch /Applications/Xcode_12_beta.app/Contents/Developer/ From 4ae47a7364dbdaa27ded8e704c2db01e4e1f00d4 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 04:15:16 +0000 Subject: [PATCH 648/663] Use latest llvm-ar and llvm-ranlib --- test/stdlib/PrintStruct.swift | 4 ---- utils/build-presets.ini | 8 ++++---- utils/webassembly/build-toolchain.sh | 1 + 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/test/stdlib/PrintStruct.swift b/test/stdlib/PrintStruct.swift index b616e61f5172a..c637d5bebf01c 100644 --- a/test/stdlib/PrintStruct.swift +++ b/test/stdlib/PrintStruct.swift @@ -4,10 +4,6 @@ // RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: executable_test -// -// FIXME Disable this case because this failed on only CI. -// Failed with 'Caught exception of type "CallIndirectOOB"' -// UNSUPPORTED: CPU=wasm32 import StdlibUnittest import PrintTestTypes diff --git a/utils/build-presets.ini b/utils/build-presets.ini index c17ae111cca89..a30812fca678a 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2645,8 +2645,8 @@ extra-cmake-options= -DSWIFT_BUILD_SOURCEKIT=FALSE -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE - -DCMAKE_AR="%(SOURCE_PATH)s/wasi-sdk/bin/llvm-ar" - -DCMAKE_RANLIB="%(SOURCE_PATH)s/wasi-sdk/bin/llvm-ranlib" + -DCMAKE_AR="%(TOOLS_BIN_DIR)s/llvm-ar" + -DCMAKE_RANLIB="%(TOOLS_BIN_DIR)s/llvm-ranlib" -DCLANG_COMPILER_RT_CMAKE_ARGS='-DCMAKE_TOOLCHAIN_FILE=%(SOURCE_PATH)s/swift/utils/webassembly/compiler-rt-cache.cmake' -DSWIFTWASM_DISABLE_REFLECTION_TEST=TRUE @@ -2664,7 +2664,7 @@ extra-cmake-options= -DSWIFT_BUILD_SOURCEKIT=FALSE -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE - -DCMAKE_AR='/usr/local/opt/llvm/bin/llvm-ar' - -DCMAKE_RANLIB='/usr/local/opt/llvm/bin/llvm-ranlib' + -DCMAKE_AR='%(TOOLS_BIN_DIR)s/llvm-ar' + -DCMAKE_RANLIB='%(TOOLS_BIN_DIR)s/llvm-ranlib' -DCLANG_COMPILER_RT_CMAKE_ARGS='-DCMAKE_TOOLCHAIN_FILE=%(SOURCE_PATH)s/swift/utils/webassembly/compiler-rt-cache.cmake' -DSWIFTWASM_DISABLE_REFLECTION_TEST=TRUE diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 7750feb17d157..684fe697b29a6 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -74,6 +74,7 @@ $SOURCE_PATH/swift/utils/build-script \ DISPLAY_NAME_SHORT="${DISPLAY_NAME_SHORT}" \ TOOLCHAIN_NAME="${TOOLCHAIN_NAME}" \ TOOLCHAIN_VERSION="${TOOLCHAIN_VERSION}" \ + TOOLS_BIN_DIR="${HOST_TOOLCHAIN_SDK}/usr/bin" \ C_CXX_LAUNCHER="$(which sccache)" # Merge wasi-sdk and the toolchain From 6c2fe9197974e53684b4fbbc611768503fac7971 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 16:01:44 +0900 Subject: [PATCH 649/663] Ignore archive uploading temporarily --- .github/workflows/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3d9bf393e31ed..aba3e918636a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,11 +45,11 @@ jobs: ./utils/webassembly/ci.sh echo "Cleanup build directory to free disk space" rm -rf ../build - - name: Upload Linux installable archive - uses: actions/upload-artifact@v1 - with: - name: linux-installable - path: ../swift-wasm-DEVELOPMENT-SNAPSHOT-linux.tar.gz +# - name: Upload Linux installable archive +# uses: actions/upload-artifact@v1 +# with: +# name: linux-installable +# path: ../swift-wasm-DEVELOPMENT-SNAPSHOT-linux.tar.gz # - name: Pack test results # run: tar cJf swift-test-results.tar.gz ../build/*/swift-linux-x86_64/swift-test-results # - name: Upload test results From 60487e6002619c931816e64e3a077682b4239b48 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 17:01:22 +0900 Subject: [PATCH 650/663] Debug with SSH --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aba3e918636a8..270de3ff54780 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -78,6 +78,7 @@ jobs: key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} restore-keys: | ${{ runner.os }}-sccache-v10- + - uses: mxschmitt/action-tmate@v1 - name: Build macOS installable archive run: | sudo xcode-select --switch /Applications/Xcode_12_beta.app/Contents/Developer/ From fa5edd0e47e7b812fa5f48071de4a96cead4f1d9 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 18:42:22 +0900 Subject: [PATCH 651/663] Install LLVM tools for host toolchain to cross build with the tools --- utils/build-presets.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index a30812fca678a..c8346fbb83e7e 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2594,6 +2594,7 @@ extra-cmake-options= llbuild swiftpm +install-llvm install-swift install-llbuild install-swiftpm From fb579479cba437201087fa5c6d775e8bf1c86a51 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 18:42:46 +0900 Subject: [PATCH 652/663] Disable SSH debug --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 270de3ff54780..aba3e918636a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -78,7 +78,6 @@ jobs: key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} restore-keys: | ${{ runner.os }}-sccache-v10- - - uses: mxschmitt/action-tmate@v1 - name: Build macOS installable archive run: | sudo xcode-select --switch /Applications/Xcode_12_beta.app/Contents/Developer/ From eecd3833c1d87717d84fedcb7e6cd164bcf8850b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 23:57:32 +0900 Subject: [PATCH 653/663] [WASM] Workaround for lld build --- utils/build-script-impl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 99f0daf80c3a3..8fcb2baba84da 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1622,12 +1622,15 @@ for host in "${ALL_HOSTS[@]}"; do # # This makes it easier to build target stdlibs on systems that # have old toolchains without more modern linker features. + # wasm: lld should be built when cross building for wasm - if [[ "$(uname -s)" != "Darwin" || ! "${SKIP_BUILD_WASM}" ]] ; then + # After enabling stdlib cross compile, add if statement + # to build only when cross compiling for wasm + # if [[ "$(uname -s)" != "Darwin" ]] ; then if [[ ! "${SKIP_BUILD_LLD}" ]]; then llvm_enable_projects+=("lld") fi - fi + # fi # wasm: SWIFT_WASI_SDK_PATH is used to determine wasi-sysroot # to build compiler-rt for wasm32-wasi From a484a6e8b1cb86a810b4686db4f82d78bda69ed0 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 23:59:06 +0900 Subject: [PATCH 654/663] Remove temporary code --- utils/webassembly/build-toolchain.sh | 5 ----- utils/webassembly/ci.sh | 6 ------ 2 files changed, 11 deletions(-) diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index 684fe697b29a6..e318698497f4d 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -52,11 +52,6 @@ $SOURCE_PATH/swift/utils/build-script \ TOOLCHAIN_NAME="$TOOLCHAIN_NAME" \ C_CXX_LAUNCHER="$(which sccache)" -if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then - echo "Exit to create a cache temporarily" - exit 0 -fi - # Clean up the host toolchain build directory so that the next # `build-script` invocation doesn't pick up wrong CMake config files. # For some reason passing `--reconfigure` to `build-script` won't do this. diff --git a/utils/webassembly/ci.sh b/utils/webassembly/ci.sh index 1a31e4520703a..c3ffb2877bbdc 100755 --- a/utils/webassembly/ci.sh +++ b/utils/webassembly/ci.sh @@ -24,12 +24,6 @@ export SCCACHE_DIR="$SOURCE_PATH/build-cache" $BUILD_SCRIPT - -if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then - echo "Exit to create a cache temporarily" - exit 0 -fi - if [[ "$(uname)" == "Darwin" ]]; then # workaround: host target test directory is necessary to use run-test mkdir -p $BUILD_DIR/swift-macosx-x86_64/test-macosx-x86_64 From 397156f6b7d7d0570eb1f76cc23a1cec26180670 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 17 Sep 2020 00:17:39 +0900 Subject: [PATCH 655/663] [WASM] Disable test/stdlib/PrintStruct.swift temporarily --- test/stdlib/PrintStruct.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/stdlib/PrintStruct.swift b/test/stdlib/PrintStruct.swift index c637d5bebf01c..b616e61f5172a 100644 --- a/test/stdlib/PrintStruct.swift +++ b/test/stdlib/PrintStruct.swift @@ -4,6 +4,10 @@ // RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: executable_test +// +// FIXME Disable this case because this failed on only CI. +// Failed with 'Caught exception of type "CallIndirectOOB"' +// UNSUPPORTED: CPU=wasm32 import StdlibUnittest import PrintTestTypes From b04dfae1cc7709e0dcd95bd7bc35ca64318e24cd Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 18 Sep 2020 09:26:45 +0900 Subject: [PATCH 656/663] Debug linux CI --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aba3e918636a8..d168082527e49 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,6 +40,7 @@ jobs: key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} restore-keys: | ${{ runner.os }}-sccache-v10- + - uses: mxschmitt/action-tmate@v3 - name: Build Linux installable archive run: | ./utils/webassembly/ci.sh From 7453696c997d96f4c1be4e781b5862ee54fb95ee Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 18 Sep 2020 09:42:21 +0900 Subject: [PATCH 657/663] Cleanup Linux container --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d168082527e49..9a16329c795fa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,6 +22,8 @@ jobs: sudo apt-get purge libgcc-9-dev gcc-9 libstdc++-9-dev sudo swapoff -a sudo rm -f /swapfile + sudo rm -rf /opt/hostedtoolcache + sudo rm -rf /usr/share/dotnet sudo apt clean docker rmi $(docker image ls -aq) df -h From ca30c6fcf30a6af02e2b8fbf421427efd9f57faa Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 18 Sep 2020 09:42:39 +0900 Subject: [PATCH 658/663] Disable debug step --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9a16329c795fa..fa7a65b1478c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,7 +42,6 @@ jobs: key: ${{ runner.os }}-sccache-v10-${{ steps.cache_timestamp.outputs.timestamp }} restore-keys: | ${{ runner.os }}-sccache-v10- - - uses: mxschmitt/action-tmate@v3 - name: Build Linux installable archive run: | ./utils/webassembly/ci.sh From fa72ced6d4adacfef6303b004615b865ca1a1f30 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 18 Sep 2020 10:33:24 +0900 Subject: [PATCH 659/663] Re-enable artifact uploading --- .github/workflows/main.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa7a65b1478c2..9ab031e17115b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,18 +47,18 @@ jobs: ./utils/webassembly/ci.sh echo "Cleanup build directory to free disk space" rm -rf ../build -# - name: Upload Linux installable archive -# uses: actions/upload-artifact@v1 -# with: -# name: linux-installable -# path: ../swift-wasm-DEVELOPMENT-SNAPSHOT-linux.tar.gz -# - name: Pack test results -# run: tar cJf swift-test-results.tar.gz ../build/*/swift-linux-x86_64/swift-test-results -# - name: Upload test results -# uses: actions/upload-artifact@v1 -# with: -# name: linux-test-results -# path: ./swift-test-results.tar.gz + - name: Upload Linux installable archive + uses: actions/upload-artifact@v1 + with: + name: linux-installable + path: ../swift-wasm-DEVELOPMENT-SNAPSHOT-linux.tar.gz + - name: Pack test results + run: tar cJf swift-test-results.tar.gz ../build/*/swift-linux-x86_64/swift-test-results + - name: Upload test results + uses: actions/upload-artifact@v1 + with: + name: linux-test-results + path: ./swift-test-results.tar.gz macos_build: timeout-minutes: 0 From a74f7b2b3dfdaa5f01f634d72ae03a44385cdc62 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 18 Sep 2020 11:35:34 +0900 Subject: [PATCH 660/663] Ignore Linux CI test failure at this time --- .github/workflows/main.yml | 14 +++++++------- utils/webassembly/ci.sh | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9ab031e17115b..7cc1602f72c3e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -52,13 +52,13 @@ jobs: with: name: linux-installable path: ../swift-wasm-DEVELOPMENT-SNAPSHOT-linux.tar.gz - - name: Pack test results - run: tar cJf swift-test-results.tar.gz ../build/*/swift-linux-x86_64/swift-test-results - - name: Upload test results - uses: actions/upload-artifact@v1 - with: - name: linux-test-results - path: ./swift-test-results.tar.gz +# - name: Pack test results +# run: tar cJf swift-test-results.tar.gz ../build/*/swift-linux-x86_64/swift-test-results +# - name: Upload test results +# uses: actions/upload-artifact@v1 +# with: +# name: linux-test-results +# path: ./swift-test-results.tar.gz macos_build: timeout-minutes: 0 diff --git a/utils/webassembly/ci.sh b/utils/webassembly/ci.sh index c3ffb2877bbdc..47881f4e9a73f 100755 --- a/utils/webassembly/ci.sh +++ b/utils/webassembly/ci.sh @@ -29,11 +29,13 @@ if [[ "$(uname)" == "Darwin" ]]; then mkdir -p $BUILD_DIR/swift-macosx-x86_64/test-macosx-x86_64 fi -$RUN_TEST_BIN --build-dir $BUILD_DIR --target wasi-wasm32 test/stdlib/ - if [[ "$(uname)" == "Linux" ]]; then + $RUN_TEST_BIN --build-dir $BUILD_DIR --target wasi-wasm32 test/stdlib/ || true echo "Skip running test suites for Linux" else + + $RUN_TEST_BIN --build-dir $BUILD_DIR --target wasi-wasm32 test/stdlib/ + # Run test but ignore failure temporarily $BUILD_SCRIPT -t || true fi From 50ec5f6a8d70df50ae9d22a342f4ba114a42db16 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 19 Sep 2020 07:59:21 +0000 Subject: [PATCH 661/663] [WASM] Always install CoreFoundation headers in target dir This avoids to conflict between static and shared module.map of CoreFoundation. The shared version of Foundation module.map doesn't require linking CoreFoundation, but build-foundation overwrite the shared version with static version. --- utils/webassembly/build-foundation.sh | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/utils/webassembly/build-foundation.sh b/utils/webassembly/build-foundation.sh index 69a1e825f3887..67b2715efaca7 100755 --- a/utils/webassembly/build-foundation.sh +++ b/utils/webassembly/build-foundation.sh @@ -24,17 +24,9 @@ cmake -G Ninja \ ninja -v ninja -v install -# On macOS the target CoreFoundation shadows the CoreFoundation suppplied by Xcode. -# On Linux though there's no system CoreFoundation, its headers have to be shipped -# in the installable archive and serve for both host and target. -if [[ "$(uname)" == "Darwin" ]]; then - mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation -else - mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation -fi +mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ + $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation # .swiftdoc and .swiftmodule files should live in `swift`, not in `swift_static` mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/wasi/wasm32/Foundation.swift* \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 \ No newline at end of file + $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 From 93df1b91462b047b71ed013f441b58b46d17adaf Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 19 Sep 2020 10:35:23 +0000 Subject: [PATCH 662/663] Revert "[WASM] Always install CoreFoundation headers in target dir" This reverts commit 50ec5f6a8d70df50ae9d22a342f4ba114a42db16. --- utils/webassembly/build-foundation.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/utils/webassembly/build-foundation.sh b/utils/webassembly/build-foundation.sh index 67b2715efaca7..69a1e825f3887 100755 --- a/utils/webassembly/build-foundation.sh +++ b/utils/webassembly/build-foundation.sh @@ -24,9 +24,17 @@ cmake -G Ninja \ ninja -v ninja -v install -mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation +# On macOS the target CoreFoundation shadows the CoreFoundation suppplied by Xcode. +# On Linux though there's no system CoreFoundation, its headers have to be shipped +# in the installable archive and serve for both host and target. +if [[ "$(uname)" == "Darwin" ]]; then + mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ + $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation +else + mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ + $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation +fi # .swiftdoc and .swiftmodule files should live in `swift`, not in `swift_static` mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/wasi/wasm32/Foundation.swift* \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 + $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 \ No newline at end of file From a0db7cbbdc21bb624101ca61a0e6017cdafac909 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 19 Sep 2020 17:31:15 +0000 Subject: [PATCH 663/663] [WASM] Refactoring build script for debuggability --- .github/workflows/main.yml | 4 +- utils/webassembly/build-foundation.sh | 20 +--- utils/webassembly/build-toolchain.sh | 127 +++++++++++++++----------- utils/webassembly/build-xctest.sh | 3 +- utils/webassembly/ci.sh | 8 +- 5 files changed, 86 insertions(+), 76 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7cc1602f72c3e..0c25e0dbd16d8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,8 +45,6 @@ jobs: - name: Build Linux installable archive run: | ./utils/webassembly/ci.sh - echo "Cleanup build directory to free disk space" - rm -rf ../build - name: Upload Linux installable archive uses: actions/upload-artifact@v1 with: @@ -90,7 +88,7 @@ jobs: name: macos-installable path: ../swift-wasm-DEVELOPMENT-SNAPSHOT-osx.tar.gz - name: Pack test results - run: tar cJf swift-test-results.tar.gz ../build/*/swift-macosx-x86_64/swift-test-results + run: tar cJf swift-test-results.tar.gz ../target-build/*/swift-macosx-x86_64/swift-test-results - name: Upload test results uses: actions/upload-artifact@v1 with: diff --git a/utils/webassembly/build-foundation.sh b/utils/webassembly/build-foundation.sh index 69a1e825f3887..9550c975780bc 100755 --- a/utils/webassembly/build-foundation.sh +++ b/utils/webassembly/build-foundation.sh @@ -3,11 +3,7 @@ set -ex DESTINATION_TOOLCHAIN=$1 SOURCE_PATH="$(cd "$(dirname $0)/../../.." && pwd)" -# Remove host CoreFoundation (which can be different from the target) headers -# to avoid shadowing the wasm32 target CoreFoundation -rm -rf $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation - -FOUNDATION_BUILD="$SOURCE_PATH/build/Ninja-ReleaseAssert/foundation-wasi-wasm32" +FOUNDATION_BUILD="$SOURCE_PATH/target-build/Ninja-ReleaseAssert/foundation-wasi-wasm32" mkdir -p $FOUNDATION_BUILD cd $FOUNDATION_BUILD @@ -19,22 +15,12 @@ cmake -G Ninja \ -DWASI_SDK_PATH="$SOURCE_PATH/wasi-sdk" \ -DICU_ROOT="$SOURCE_PATH/icu_out" \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_Swift_COMPILER_FORCED=ON \ "${SOURCE_PATH}/swift-corelibs-foundation" ninja -v ninja -v install -# On macOS the target CoreFoundation shadows the CoreFoundation suppplied by Xcode. -# On Linux though there's no system CoreFoundation, its headers have to be shipped -# in the installable archive and serve for both host and target. -if [[ "$(uname)" == "Darwin" ]]; then - mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation -else - mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation -fi - # .swiftdoc and .swiftmodule files should live in `swift`, not in `swift_static` mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/wasi/wasm32/Foundation.swift* \ - $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 \ No newline at end of file + $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 diff --git a/utils/webassembly/build-toolchain.sh b/utils/webassembly/build-toolchain.sh index e318698497f4d..527556c0d87b2 100755 --- a/utils/webassembly/build-toolchain.sh +++ b/utils/webassembly/build-toolchain.sh @@ -11,11 +11,13 @@ case $(uname -s) in OS_SUFFIX=osx HOST_PRESET=webassembly-host TARGET_PRESET=webassembly-macos-target + HOST_SUFFIX=macosx-x86_64 ;; Linux) OS_SUFFIX=linux HOST_PRESET=webassembly-linux-host TARGET_PRESET=webassembly-linux-target + HOST_SUFFIX=linux-x86_64 ;; *) echo "Unrecognised platform $(uname -s)" @@ -29,7 +31,6 @@ DAY=$(date +"%d") TOOLCHAIN_VERSION="${YEAR}${MONTH}${DAY}" TOOLCHAIN_NAME="swift-wasm-DEVELOPMENT-SNAPSHOT-${YEAR}-${MONTH}-${DAY}-a" ARCHIVE="${TOOLCHAIN_NAME}-${OS_SUFFIX}.tar.gz" -INSTALLABLE_PACKAGE=$SOURCE_PATH/$ARCHIVE PACKAGE_ARTIFACT="$SOURCE_PATH/swift-wasm-DEVELOPMENT-SNAPSHOT-${OS_SUFFIX}.tar.gz" @@ -37,61 +38,85 @@ BUNDLE_IDENTIFIER="swiftwasm.${YEAR}${MONTH}${DAY}" DISPLAY_NAME_SHORT="Swift for WebAssembly Development Snapshot" DISPLAY_NAME="${DISPLAY_NAME_SHORT} ${YEAR}-${MONTH}-${DAY}" +DIST_TOOLCHAIN_DESTDIR=$SOURCE_PATH/dist-toolchain-sdk HOST_TOOLCHAIN_DESTDIR=$SOURCE_PATH/host-toolchain-sdk +TARGET_TOOLCHAIN_DESTDIR=$SOURCE_PATH/target-toolchain-sdk + +DIST_TOOLCHAIN_SDK=$DIST_TOOLCHAIN_DESTDIR/$TOOLCHAIN_NAME HOST_TOOLCHAIN_SDK=$HOST_TOOLCHAIN_DESTDIR/$TOOLCHAIN_NAME +TARGET_TOOLCHAIN_SDK=$TARGET_TOOLCHAIN_DESTDIR/$TOOLCHAIN_NAME + -BUILD_DIR=$SOURCE_PATH/build/Ninja-ReleaseAssert +HOST_BUILD_ROOT=$SOURCE_PATH/host-build +TARGET_BUILD_ROOT=$SOURCE_PATH/target-build +HOST_BUILD_DIR=$HOST_BUILD_ROOT/Ninja-ReleaseAssert +TARGET_BUILD_DIR=$TARGET_BUILD_ROOT/Ninja-ReleaseAssert # Avoid clang headers symlink issues mkdir -p $HOST_TOOLCHAIN_SDK/usr/lib/clang/10.0.0 -# Build the host toolchain and SDK first. -$SOURCE_PATH/swift/utils/build-script \ - --preset=$HOST_PRESET \ - INSTALL_DESTDIR="$HOST_TOOLCHAIN_DESTDIR" \ - TOOLCHAIN_NAME="$TOOLCHAIN_NAME" \ - C_CXX_LAUNCHER="$(which sccache)" - -# Clean up the host toolchain build directory so that the next -# `build-script` invocation doesn't pick up wrong CMake config files. -# For some reason passing `--reconfigure` to `build-script` won't do this. -rm -rf $BUILD_DIR/swift-* -# Clean up compiler-rt dir to cross compile it for host and wasm32 -(cd $BUILD_DIR/llvm-* && ninja compiler-rt-clear) - -# build the cross-compilled toolchain -$SOURCE_PATH/swift/utils/build-script \ - --preset=$TARGET_PRESET --reconfigure \ - INSTALL_DESTDIR="$SOURCE_PATH/install" \ - SOURCE_PATH="$SOURCE_PATH" \ - BUNDLE_IDENTIFIER="${BUNDLE_IDENTIFIER}" \ - DISPLAY_NAME="${DISPLAY_NAME}" \ - DISPLAY_NAME_SHORT="${DISPLAY_NAME_SHORT}" \ - TOOLCHAIN_NAME="${TOOLCHAIN_NAME}" \ - TOOLCHAIN_VERSION="${TOOLCHAIN_VERSION}" \ - TOOLS_BIN_DIR="${HOST_TOOLCHAIN_SDK}/usr/bin" \ - C_CXX_LAUNCHER="$(which sccache)" - -# Merge wasi-sdk and the toolchain -cp -r $WASI_SDK_PATH/share/wasi-sysroot $HOST_TOOLCHAIN_SDK/usr/share - -# Replace absolute sysroot path with relative path -sed -i -e "s@\".*/include@\"../../../../share/wasi-sysroot/include@g" $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/lib/swift/wasi/wasm32/glibc.modulemap - -# Copy the target environment stdlib into the toolchain - -# Avoid copying usr/lib/swift/clang because our toolchain's one is a directory -# but nightly's one is symbolic link. A simple copy fails to merge them. -rsync -v -a $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/lib/ $HOST_TOOLCHAIN_SDK/usr/lib/ --exclude 'swift/clang' -rsync -v -a $SOURCE_PATH/install/$TOOLCHAIN_NAME/usr/bin/ $HOST_TOOLCHAIN_SDK/usr/bin/ - -$UTILS_PATH/build-foundation.sh $HOST_TOOLCHAIN_SDK -$UTILS_PATH/build-xctest.sh $HOST_TOOLCHAIN_SDK - -# Cleanup build directory on Linux CI -if [[ -n "${CI}" && "$(uname)" == "Linux" ]]; then - rm -rf $BUILD_DIR/foundation-* $BUILD_DIR/swiftpm-* -fi - -cd $HOST_TOOLCHAIN_DESTDIR +build_host_toolchain() { + # Build the host toolchain and SDK first. + env SWIFT_BUILD_ROOT="$HOST_BUILD_ROOT" \ + $SOURCE_PATH/swift/utils/build-script \ + --preset=$HOST_PRESET \ + --build-dir="$HOST_BUILD_DIR" \ + INSTALL_DESTDIR="$HOST_TOOLCHAIN_DESTDIR" \ + TOOLCHAIN_NAME="$TOOLCHAIN_NAME" \ + C_CXX_LAUNCHER="$(which sccache)" +} + +build_target_toolchain() { + mkdir -p $HOST_BUILD_DIR/ + # Copy the host build dir to reuse it. + if [[ ! -e "$HOST_BUILD_DIR/llvm-$HOST_SUFFIX" ]]; then + cp -r "$HOST_BUILD_DIR/llvm-$HOST_SUFFIX" "$TARGET_BUILD_DIR/llvm-$HOST_SUFFIX" + # Clean up compiler-rt dir to cross compile it for host and wasm32 + (cd "$TARGET_BUILD_DIR/llvm-$HOST_SUFFIX" && ninja compiler-rt-clear) + fi + + # build the cross-compilled toolchain + env SWIFT_BUILD_ROOT="$TARGET_BUILD_ROOT" \ + $SOURCE_PATH/swift/utils/build-script \ + --preset=$TARGET_PRESET --reconfigure \ + --build-dir="$TARGET_BUILD_DIR" \ + INSTALL_DESTDIR="$TARGET_TOOLCHAIN_DESTDIR" \ + SOURCE_PATH="$SOURCE_PATH" \ + BUNDLE_IDENTIFIER="${BUNDLE_IDENTIFIER}" \ + DISPLAY_NAME="${DISPLAY_NAME}" \ + DISPLAY_NAME_SHORT="${DISPLAY_NAME_SHORT}" \ + TOOLCHAIN_NAME="${TOOLCHAIN_NAME}" \ + TOOLCHAIN_VERSION="${TOOLCHAIN_VERSION}" \ + TOOLS_BIN_DIR="${HOST_TOOLCHAIN_SDK}/usr/bin" \ + C_CXX_LAUNCHER="$(which sccache)" + + $UTILS_PATH/build-foundation.sh $TARGET_TOOLCHAIN_SDK + $UTILS_PATH/build-xctest.sh $TARGET_TOOLCHAIN_SDK + +} + +merge_toolchains() { + rm -rf "$DIST_TOOLCHAIN_DESTDIR" + # Copy the base host toolchain + cp -r "$HOST_TOOLCHAIN_DESTDIR" "$DIST_TOOLCHAIN_DESTDIR" + + # Merge wasi-sdk and the toolchain + cp -r $WASI_SDK_PATH/share/wasi-sysroot $DIST_TOOLCHAIN_SDK/usr/share + + # Copy the target environment stdlib into the toolchain + # Avoid copying usr/lib/swift/clang because our toolchain's one is a directory + # but nightly's one is symbolic link. A simple copy fails to merge them. + rsync -v -a $TARGET_TOOLCHAIN_SDK/usr/lib/ $DIST_TOOLCHAIN_SDK/usr/lib/ --exclude 'swift/clang' + rsync -v -a $TARGET_TOOLCHAIN_SDK/usr/bin/ $DIST_TOOLCHAIN_SDK/usr/bin/ + + # Replace absolute sysroot path with relative path + sed -i -e "s@\".*/include@\"../../../../share/wasi-sysroot/include@g" $DIST_TOOLCHAIN_SDK/usr/lib/swift/wasi/wasm32/glibc.modulemap +} + +build_host_toolchain +build_target_toolchain + +merge_toolchains + +cd $DIST_TOOLCHAIN_DESTDIR tar cfz $PACKAGE_ARTIFACT $TOOLCHAIN_NAME diff --git a/utils/webassembly/build-xctest.sh b/utils/webassembly/build-xctest.sh index e08e0cef33db1..fe93f244ce0b3 100755 --- a/utils/webassembly/build-xctest.sh +++ b/utils/webassembly/build-xctest.sh @@ -3,7 +3,7 @@ set -ex DESTINATION_TOOLCHAIN=$1 SOURCE_PATH="$(cd "$(dirname $0)/../../.." && pwd)" -BUILD_DIR="$SOURCE_PATH/build/Ninja-ReleaseAssert/xctest-wasi-wasm32" +BUILD_DIR="$SOURCE_PATH/target-build/Ninja-ReleaseAssert/xctest-wasi-wasm32" mkdir -p $BUILD_DIR cd $BUILD_DIR @@ -14,6 +14,7 @@ cmake -G Ninja \ -DCMAKE_TOOLCHAIN_FILE="$SOURCE_PATH/swift/utils/webassembly/toolchain-wasi.cmake" \ -DWASI_SDK_PATH="$SOURCE_PATH/wasi-sdk" \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_Swift_COMPILER_FORCED=ON \ -DSWIFT_FOUNDATION_PATH=$DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 \ "${SOURCE_PATH}/swift-corelibs-xctest" diff --git a/utils/webassembly/ci.sh b/utils/webassembly/ci.sh index 47881f4e9a73f..6da8cf9f4b86a 100755 --- a/utils/webassembly/ci.sh +++ b/utils/webassembly/ci.sh @@ -13,7 +13,7 @@ fi BUILD_SCRIPT=$UTILS_PATH/build-toolchain.sh RUN_TEST_BIN=$SWIFT_PATH/utils/run-test -BUILD_DIR=$SOURCE_PATH/build/Ninja-ReleaseAssert +TARGET_BUILD_DIR=$SOURCE_PATH/target-build/Ninja-ReleaseAssert $DEPENDENCIES_SCRIPT @@ -26,15 +26,15 @@ $BUILD_SCRIPT if [[ "$(uname)" == "Darwin" ]]; then # workaround: host target test directory is necessary to use run-test - mkdir -p $BUILD_DIR/swift-macosx-x86_64/test-macosx-x86_64 + mkdir -p $TARGET_BUILD_DIR/swift-macosx-x86_64/test-macosx-x86_64 fi if [[ "$(uname)" == "Linux" ]]; then - $RUN_TEST_BIN --build-dir $BUILD_DIR --target wasi-wasm32 test/stdlib/ || true + $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 test/stdlib/ || true echo "Skip running test suites for Linux" else - $RUN_TEST_BIN --build-dir $BUILD_DIR --target wasi-wasm32 test/stdlib/ + $RUN_TEST_BIN --build-dir $TARGET_BUILD_DIR --target wasi-wasm32 test/stdlib/ # Run test but ignore failure temporarily $BUILD_SCRIPT -t || true

, + s: String) { _ = concreteBase[keyPath: kp] _ = concreteBase[keyPath: wkp] _ = concreteBase[keyPath: rkp] @@ -457,9 +457,7 @@ func testKeyPathSubscriptExistentialBase(concreteBase: inout B, concreteBase[keyPath: kp] = s // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}} concreteBase[keyPath: wkp] = s // expected-error {{key path with root type 'P' cannot be applied to a base of type 'B'}} concreteBase[keyPath: rkp] = s - // TODO(diagnostics): Improve this diagnostic message because concreteBase is mutable, the problem is related to assign - // through PartialKeyPath. - concreteBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'concreteBase' is immutable}} + concreteBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'pkp' is a read-only key path}} _ = existentialBase[keyPath: kp] _ = existentialBase[keyPath: wkp] @@ -469,9 +467,7 @@ func testKeyPathSubscriptExistentialBase(concreteBase: inout B, existentialBase[keyPath: kp] = s // expected-error {{cannot assign through subscript: 'kp' is a read-only key path}} existentialBase[keyPath: wkp] = s existentialBase[keyPath: rkp] = s - // TODO(diagnostics): Improve this diagnostic message because existentialBase is mutable, the problem is related to assign - // through PartialKeyPath. - existentialBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'existentialBase' is immutable}} + existentialBase[keyPath: pkp] = s // expected-error {{cannot assign through subscript: 'pkp' is a read-only key path}} } struct AA { From 28a2826ef4ceab722cd1f957fa573b2d474a7ff4 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Mon, 17 Aug 2020 19:26:24 -0700 Subject: [PATCH 201/663] Start using optimization (-O0/-O2/-O3/-Os) and debug (-g) flags from CMAKE_CXX_FLAGS_${CFLAGS_BUILD_TYPE} (#33388) --- CMakeLists.txt | 15 +++++++++ cmake/modules/AddSwift.cmake | 38 ++++++----------------- stdlib/cmake/modules/AddSwiftStdlib.cmake | 38 ++++++----------------- utils/build-script-impl | 4 --- 4 files changed, 33 insertions(+), 62 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82e07d6244b2f..cf0d50a51948d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -633,6 +633,21 @@ if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQU set(SWIFT_COMPILER_IS_MSVC_LIKE TRUE) endif() +if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) + # CMake's default for CMAKE_CXX_FLAGS_RELEASE is "-O3 -DNDEBUG". Let's avoid "-O3" for consistency + # between Release and RelWithDebInfo. And let's not set -DNDEBUG because we're setting that manually + # based on LLVM_ENABLE_ASSERTIONS. + set(CMAKE_CXX_FLAGS_RELEASE "-O2") + + _compute_lto_flag("${SWIFT_TOOLS_ENABLE_LTO}" _lto_flag_out) + if(_lto_flag_out) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_RELEASE} -gline-tables-only") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -gline-tables-only") + endif() +else() + +endif() + # # Configure SDKs. # diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index ec61d2abb836a..863095fdfa205 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -130,17 +130,18 @@ function(_add_host_variant_c_compile_flags target) _add_host_variant_c_compile_link_flags(${target}) is_build_type_optimized("${CMAKE_BUILD_TYPE}" optimized) - if(optimized) - if("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel") - target_compile_options(${target} PRIVATE -Os) - else() - target_compile_options(${target} PRIVATE -O2) - endif() + is_build_type_with_debuginfo("${CMAKE_BUILD_TYPE}" debuginfo) + + # Add -O0/-O2/-O3/-Os/-g/-momit-leaf-frame-pointer/... based on CMAKE_BUILD_TYPE. + target_compile_options(${target} PRIVATE "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}") + if(optimized) # Omit leaf frame pointers on x86 production builds (optimized, no debug # info, and no asserts). - is_build_type_with_debuginfo("${CMAKE_BUILD_TYPE}" debug) - if(NOT debug AND NOT LLVM_ENABLE_ASSERTIONS) + if(NOT debuginfo AND NOT LLVM_ENABLE_ASSERTIONS) + # Unfortunately, this cannot be folded into the standard + # CMAKE_CXX_FLAGS_... because Apple multi-SDK builds use different + # architectures for different SDKs. if(SWIFT_HOST_VARIANT_ARCH MATCHES "i?86") if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) target_compile_options(${target} PRIVATE -momit-leaf-frame-pointer) @@ -149,27 +150,6 @@ function(_add_host_variant_c_compile_flags target) endif() endif() endif() - else() - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - target_compile_options(${target} PRIVATE -O0) - else() - target_compile_options(${target} PRIVATE /Od) - endif() - endif() - - # CMake automatically adds the flags for debug info if we use MSVC/clang-cl. - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - is_build_type_with_debuginfo("${CMAKE_BUILD_TYPE}" debuginfo) - if(debuginfo) - _compute_lto_flag("${SWIFT_TOOLS_ENABLE_LTO}" _lto_flag_out) - if(_lto_flag_out) - target_compile_options(${target} PRIVATE -gline-tables-only) - else() - target_compile_options(${target} PRIVATE -g) - endif() - else() - target_compile_options(${target} PRIVATE -g0) - endif() endif() if(SWIFT_HOST_VARIANT_SDK STREQUAL WINDOWS) diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 7f5ca365da53d..a751a1da805a0 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -164,17 +164,18 @@ function(_add_target_variant_c_compile_flags) MACCATALYST_BUILD_FLAVOR "${CFLAGS_MACCATALYST_BUILD_FLAVOR}") is_build_type_optimized("${CFLAGS_BUILD_TYPE}" optimized) - if(optimized) - if("${CFLAGS_BUILD_TYPE}" STREQUAL "MinSizeRel") - list(APPEND result "-Os") - else() - list(APPEND result "-O2") - endif() + is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debuginfo) + + # Add -O0/-O2/-O3/-Os/-g/... based on CFLAGS_BUILD_TYPE. + list(APPEND result "${CMAKE_CXX_FLAGS_${CFLAGS_BUILD_TYPE}}") + if(optimized) # Omit leaf frame pointers on x86 production builds (optimized, no debug # info, and no asserts). - is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debug) - if(NOT debug AND NOT CFLAGS_ENABLE_ASSERTIONS) + if(NOT debuginfo AND NOT CFLAGS_ENABLE_ASSERTIONS) + # Unfortunately, this cannot be folded into the standard + # CMAKE_CXX_FLAGS_... because Apple multi-SDK builds use different + # architectures for different SDKs (CFLAGS_ARCH isn't constant here). if("${CFLAGS_ARCH}" STREQUAL "i386" OR "${CFLAGS_ARCH}" STREQUAL "i686") if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) list(APPEND result "-momit-leaf-frame-pointer") @@ -183,27 +184,6 @@ function(_add_target_variant_c_compile_flags) endif() endif() endif() - else() - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - list(APPEND result "-O0") - else() - list(APPEND result "/Od") - endif() - endif() - - # CMake automatically adds the flags for debug info if we use MSVC/clang-cl. - if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) - is_build_type_with_debuginfo("${CFLAGS_BUILD_TYPE}" debuginfo) - if(debuginfo) - _compute_lto_flag("${CFLAGS_ENABLE_LTO}" _lto_flag_out) - if(_lto_flag_out) - list(APPEND result "-gline-tables-only") - else() - list(APPEND result "-g") - endif() - else() - list(APPEND result "-g0") - endif() endif() if("${CFLAGS_SDK}" STREQUAL "WINDOWS") diff --git a/utils/build-script-impl b/utils/build-script-impl index b9f51aeae1060..572f6c20a00f1 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1576,8 +1576,6 @@ for host in "${ALL_HOSTS[@]}"; do "${cmake_options[@]}" -DCMAKE_C_FLAGS="$(llvm_c_flags ${host})" -DCMAKE_CXX_FLAGS="$(llvm_c_flags ${host})" - -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" - -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" -DCMAKE_BUILD_TYPE:STRING="${LLVM_BUILD_TYPE}" -DLLVM_TOOL_SWIFT_BUILD:BOOL=NO -DLLVM_TOOL_LLD_BUILD:BOOL=TRUE @@ -1756,8 +1754,6 @@ for host in "${ALL_HOSTS[@]}"; do "${cmake_options[@]}" -DCMAKE_C_FLAGS="$(swift_c_flags ${host})" -DCMAKE_CXX_FLAGS="$(swift_c_flags ${host})" - -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" - -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG" -DCMAKE_BUILD_TYPE:STRING="${SWIFT_BUILD_TYPE}" -DLLVM_ENABLE_ASSERTIONS:BOOL=$(true_false "${SWIFT_ENABLE_ASSERTIONS}") -DSWIFT_ANALYZE_CODE_COVERAGE:STRING=$(toupper "${SWIFT_ANALYZE_CODE_COVERAGE}") From ee1d975da065afbb67acafaf26098e4d13986861 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Mon, 17 Aug 2020 19:27:26 -0700 Subject: [PATCH 202/663] Disable test for asan builds Raises a stackoverflow error in some asan builds even though it is not a runaway recursion. --- validation-test/ParseableInterface/verify_all_overlays.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation-test/ParseableInterface/verify_all_overlays.py b/validation-test/ParseableInterface/verify_all_overlays.py index 631ddd0666a92..e1ce62e248f54 100755 --- a/validation-test/ParseableInterface/verify_all_overlays.py +++ b/validation-test/ParseableInterface/verify_all_overlays.py @@ -12,7 +12,7 @@ # RUN: test ! -e %t/failures.txt || \ # RUN: diff %t/filter.txt %t/failures.txt -# REQUIRES: nonexecutable_test +# REQUIRES: nonexecutable_test, no_asan # Expected failures by platform # ----------------------------- From 7a9f894c88b9922e534192ec0dbbc876602f0895 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Mon, 17 Aug 2020 20:58:54 -0700 Subject: [PATCH 203/663] =?UTF-8?q?Avoid=20using=20-sil-inline-generics=20?= =?UTF-8?q?and=20-sil-partial-specialization=20when=20building=20MinSizeRe?= =?UTF-8?q?l=20stdlib=20to=20save=C2=A0~15%=20on=20codesize=20(#33444)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stdlib/public/core/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 5cb634ad1d360..56d9d5d230154 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -287,8 +287,10 @@ if(SWIFT_STDLIB_SIL_DEBUGGING) list(APPEND swift_stdlib_compile_flags "-Xfrontend" "-gsil") endif() -list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-inline-generics") -list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-partial-specialization") +if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel") + list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-inline-generics") + list(APPEND swift_stdlib_compile_flags "-Xllvm" "-sil-partial-specialization") +endif() if(SWIFT_STDLIB_ENABLE_STDLIBCORE_EXCLUSIVITY_CHECKING) list(APPEND swift_stdlib_compile_flags "-enforce-exclusivity=checked") endif() From a5cf594a5b03244837c16c62fb8e82ef74ddbfc0 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 17 Aug 2020 21:36:35 -0700 Subject: [PATCH 204/663] [opt-remark] Re-enable test case removing even more stdlib specific type names. No more references to any Array, ContiguousArray, etc. So we should be ok. rdar://66330768 --- test/SILOptimizer/opt-remark-generator-yaml.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/SILOptimizer/opt-remark-generator-yaml.swift b/test/SILOptimizer/opt-remark-generator-yaml.swift index 11e3dbb7f9d25..3dcd9fd051f5c 100644 --- a/test/SILOptimizer/opt-remark-generator-yaml.swift +++ b/test/SILOptimizer/opt-remark-generator-yaml.swift @@ -1,4 +1,3 @@ -// REQUIRES: rdar66330768 // RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify // RUN: %empty-directory(%t) @@ -54,7 +53,7 @@ public func getGlobal() -> Klass { // CHECK-NEXT: Function: 'useGlobal()' // CHECK-NEXT: Args: // CHECK-NEXT: - String: 'release of type ''' -// CHECK-NEXT: - ValueType: {{'Array'|__ContiguousArrayStorageBase}} +// CHECK-NEXT: - ValueType: // CHECK-NEXT: - String: '''' // CHECK-NEXT: ... // CHECK-NEXT: --- !Missed From 99889112324f2b16bd110f41e470df3d1242932b Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Mon, 17 Aug 2020 16:59:06 -0700 Subject: [PATCH 205/663] Frontend: add a new action -scan-clang-dependencies to scan a PCM's dependencies For the issue mentioned in rdar://67079780, swift-driver needs to run clang dependencies scanner multiple times with different target triples for a Swift target. This patch adds a new scanning action to generate the JSON file for a given clang module to accommodate this requirement. Resolves: rdar://problem/67269210 --- include/swift/Frontend/FrontendOptions.h | 3 +- include/swift/Option/Options.td | 4 ++ .../ArgsToFrontendOptionsConverter.cpp | 2 + lib/Frontend/FrontendOptions.cpp | 13 +++++ lib/FrontendTool/FrontendTool.cpp | 3 ++ lib/FrontendTool/ScanDependencies.cpp | 50 +++++++++++++++++++ lib/FrontendTool/ScanDependencies.h | 4 ++ .../module_deps_clang_only.swift | 21 ++++++++ 8 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 test/ScanDependencies/module_deps_clang_only.swift diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index aef89085fb34b..e1644051c10e6 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -133,7 +133,8 @@ class FrontendOptions { EmitPCM, ///< Emit precompiled Clang module from a module map DumpPCM, ///< Dump information about a precompiled Clang module - ScanDependencies, ///< Scan dependencies of Swift source files + ScanDependencies, ///< Scan dependencies of Swift source files + ScanClangDependencies, ///< Scan dependencies of a Clang module PrintVersion, ///< Print version information. }; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 01017c43315eb..b5b4f57eae9c3 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1094,6 +1094,10 @@ def scan_dependencies : Flag<["-"], "scan-dependencies">, HelpText<"Scan dependencies of the given Swift sources">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; +def scan_clang_dependencies : Flag<["-"], "scan-clang-dependencies">, + HelpText<"Scan dependencies of the given Clang module">, ModeOpt, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; + def enable_astscope_lookup : Flag<["-"], "enable-astscope-lookup">, Flags<[FrontendOption]>, HelpText<"Enable ASTScope-based unqualified name lookup">; diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 05b0ed04f5083..2588d9084b3fb 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -354,6 +354,8 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) { return FrontendOptions::ActionType::EmitImportedModules; if (Opt.matches(OPT_scan_dependencies)) return FrontendOptions::ActionType::ScanDependencies; + if (Opt.matches(OPT_scan_clang_dependencies)) + return FrontendOptions::ActionType::ScanClangDependencies; if (Opt.matches(OPT_parse)) return FrontendOptions::ActionType::Parse; if (Opt.matches(OPT_resolve_imports)) diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 1e1253ddcb6c5..e3a2701960909 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -64,6 +64,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::DumpTypeInfo: case ActionType::EmitPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return true; } llvm_unreachable("Unknown ActionType"); @@ -77,6 +78,7 @@ bool FrontendOptions::shouldActionOnlyParse(ActionType action) { case FrontendOptions::ActionType::DumpInterfaceHash: case FrontendOptions::ActionType::EmitImportedModules: case FrontendOptions::ActionType::ScanDependencies: + case FrontendOptions::ActionType::ScanClangDependencies: case FrontendOptions::ActionType::PrintVersion: return true; default: @@ -174,6 +176,7 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { return TY_ClangModuleFile; case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return TY_JSONDependencies; } llvm_unreachable("unhandled action"); @@ -213,6 +216,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::EmitImportedModules: case ActionType::EmitPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return true; } llvm_unreachable("unhandled action"); @@ -237,6 +241,7 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::Typecheck: @@ -285,6 +290,7 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::Typecheck: @@ -322,6 +328,7 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::ResolveImports: @@ -365,6 +372,7 @@ bool FrontendOptions::canActionEmitModule(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::MergeModules: @@ -409,6 +417,7 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return false; case ActionType::Typecheck: case ActionType::MergeModules: @@ -454,6 +463,7 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: return true; case ActionType::NoneAction: @@ -499,6 +509,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::DumpTypeInfo: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return true; } @@ -524,6 +535,7 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::EmitSILGen: @@ -570,6 +582,7 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { case ActionType::EmitPCM: case ActionType::DumpPCM: case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: case ActionType::PrintVersion: return false; case ActionType::Immediate: diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 3dfa4312e7574..9bdfe3e1da24b 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1836,6 +1836,9 @@ static bool performCompile(CompilerInstance &Instance, if (Action == FrontendOptions::ActionType::ScanDependencies) return finishPipeline(scanDependencies(Instance)); + if (Action == FrontendOptions::ActionType::ScanClangDependencies) + return finishPipeline(scanClangDependencies(Instance)); + if (observer) observer->performedSemanticAnalysis(Instance); diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index df2829276e526..bf2fccc25de93 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -533,6 +533,56 @@ static bool diagnoseCycle(CompilerInstance &instance, return false; } +bool swift::scanClangDependencies(CompilerInstance &instance) { + ASTContext &ctx = instance.getASTContext(); + ModuleDecl *mainModule = instance.getMainModule(); + auto &FEOpts = instance.getInvocation().getFrontendOptions(); + ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); + auto ModuleCachePath = getModuleCachePathFromClang(ctx + .getClangModuleLoader()->getClangInstance()); + + StringRef mainModuleName = mainModule->getNameStr(); + llvm::SetVector, + std::set> allModules; + // Create the module dependency cache. + ModuleDependenciesCache cache; + InterfaceSubContextDelegateImpl ASTDelegate(ctx.SourceMgr, ctx.Diags, + ctx.SearchPathOpts, ctx.LangOpts, + LoaderOpts, + ctx.getClangModuleLoader(), + /*buildModuleCacheDirIfAbsent*/false, + ModuleCachePath, + FEOpts.PrebuiltModuleCachePath, + FEOpts.SerializeModuleInterfaceDependencyHashes, + FEOpts.shouldTrackSystemDependencies()); + // Loading the clang module using Clang importer. + // This action will populate the cache with the main module's dependencies. + auto rootDeps = static_cast(ctx.getClangModuleLoader()) + ->getModuleDependencies(mainModuleName, cache, ASTDelegate); + if (!rootDeps.hasValue()) { + // We cannot find the clang module, abort. + return true; + } + // Add the main module. + allModules.insert({mainModuleName.str(), ModuleDependenciesKind::Clang}); + + // Explore the dependencies of every module. + for (unsigned currentModuleIdx = 0; + currentModuleIdx < allModules.size(); + ++currentModuleIdx) { + auto module = allModules[currentModuleIdx]; + auto discoveredModules = + resolveDirectDependencies(instance, module, cache, ASTDelegate); + allModules.insert(discoveredModules.begin(), discoveredModules.end()); + } + // Write out the JSON description. + std::string path = FEOpts.InputsAndOutputs.getSingleOutputFilename(); + std::error_code EC; + llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None); + writeJSON(out, instance, cache, ASTDelegate, allModules.getArrayRef()); + return false; +} + bool swift::scanDependencies(CompilerInstance &instance) { ASTContext &Context = instance.getASTContext(); ModuleDecl *mainModule = instance.getMainModule(); diff --git a/lib/FrontendTool/ScanDependencies.h b/lib/FrontendTool/ScanDependencies.h index ece8515097608..e3ed171c2badb 100644 --- a/lib/FrontendTool/ScanDependencies.h +++ b/lib/FrontendTool/ScanDependencies.h @@ -20,6 +20,10 @@ class CompilerInstance; /// Scans the dependencies of the main module of \c instance. bool scanDependencies(CompilerInstance &instance); +/// Scans the dependencies of the underlying clang module of the main module +/// of \c instance. +bool scanClangDependencies(CompilerInstance &instance); + } // end namespace swift #endif diff --git a/test/ScanDependencies/module_deps_clang_only.swift b/test/ScanDependencies/module_deps_clang_only.swift new file mode 100644 index 0000000000000..e406bacd74889 --- /dev/null +++ b/test/ScanDependencies/module_deps_clang_only.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: %target-swift-frontend -scan-clang-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules -module-name C + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json + +// CHECK: "mainModuleName": "C", +// CHECK-NEXT: "modules": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "C" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "modulePath": "C.pcm", +// CHECK-NEXT: "sourceFiles": [ + + +// CHECK: "directDependencies": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "B" +// CHECK-NEXT: } From 9ea0741587d3b2bc6ae961568f3afabdd38b5ffb Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 15 Aug 2020 00:33:45 -0400 Subject: [PATCH 206/663] Sema: Carefully tweak shadowing rules TypeChecker::lookupMemberType() performs a lookup on the base type, and disambiguates multiple results by filtering out result decls that have canonically equal types under the base type substitution. I'd like to refactor conformance checking to call lookupQualified() directly and bypass lookupMemberType(), but this requires adding a new shadowing rule to primitive name lookup to simulate the effect of the type-based disambiguation. We already had a shadowing rule which states that concrete type members shadow protocol members of the same name, but this was bypassed for member _types_. This change generalizes this rule to apply to member types also. Hopefully this doesn't break source compatibility in practice. --- lib/AST/NameLookup.cpp | 13 +++++++++++++ test/NameLookup/member_type_shadowing.swift | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index fdbfb119ebddb..b581137926415 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -312,6 +312,19 @@ static void recordShadowedDeclsAfterTypeMatch( } } + // If one declaration is in a protocol or extension thereof and the + // other is not, prefer the one that is not. + if ((bool)firstDecl->getDeclContext()->getSelfProtocolDecl() != + (bool)secondDecl->getDeclContext()->getSelfProtocolDecl()) { + if (firstDecl->getDeclContext()->getSelfProtocolDecl()) { + shadowed.insert(firstDecl); + break; + } else { + shadowed.insert(secondDecl); + continue; + } + } + continue; } diff --git a/test/NameLookup/member_type_shadowing.swift b/test/NameLookup/member_type_shadowing.swift index 3ce67db444956..0e3b4f7a81b9d 100644 --- a/test/NameLookup/member_type_shadowing.swift +++ b/test/NameLookup/member_type_shadowing.swift @@ -29,3 +29,17 @@ class B: A { _ = B.Reusable.option2 // expected-error {{type 'B.Reusable' has no member 'option2'; did you mean 'option1'?}} } } + +protocol Q { + typealias A = Int +} + +struct S : Q { + typealias A = String +} + +func usesA(_: S.A) {} // should resolve to the typealias inside S + +func callsA() { + usesA("hello") +} From c4725f6a156a20ac0b3f0961b6b1f8bb6e7ab362 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 15 Aug 2020 00:11:58 -0400 Subject: [PATCH 207/663] Sema: Refactor resolveTypeWitnessViaLookup() to call lookupQualified() directly lookupMemberType() does additional things that we don't need here. By using lookupQualified() we can avoid realizing the substituted type until after checking the 'where' clause constraints. This should (in theory, at least) break cycles where performing the substitution triggers a recursive conformance check. --- lib/Sema/TypeCheckProtocol.cpp | 90 ++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 31 deletions(-) diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 8de95a8d88c57..bac55fa09978c 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3862,58 +3862,86 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( abort(); } + NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers); + // Look for a member type with the same name as the associated type. - auto candidates = TypeChecker::lookupMemberType( - DC, Adoptee, assocType->createNameRef(), - NameLookupFlags::ProtocolMembers); + SmallVector candidates; + + DC->lookupQualified(Adoptee->getAnyNominal(), + assocType->createNameRef(), + subOptions, candidates); // If there aren't any candidates, we're done. - if (!candidates) { + if (candidates.empty()) { return ResolveWitnessResult::Missing; } // Determine which of the candidates is viable. SmallVector viable; SmallVector, 2> nonViable; + SmallPtrSet viableTypes; + for (auto candidate : candidates) { - // Skip nested generic types. - if (auto *genericDecl = dyn_cast(candidate.Member)) { - // If the declaration has generic parameters, it cannot witness an - // associated type. - if (genericDecl->isGeneric()) - continue; + auto *typeDecl = cast(candidate); - // As a narrow fix for a source compatibility issue with SwiftUI's - // swiftinterface, allow the conformance if the underlying type of - // the typealias is Never. - // - // FIXME: This should be conditionalized on a new language version. - bool skipRequirementCheck = false; - if (auto *typeAliasDecl = dyn_cast(candidate.Member)) { - if (typeAliasDecl->getUnderlyingType()->isUninhabited()) - skipRequirementCheck = true; - } + // Skip other associated types. + if (isa(typeDecl)) + continue; - // If the type comes from a constrained extension or has a 'where' - // clause, check those requirements now. - if (!skipRequirementCheck && - !TypeChecker::checkContextualRequirements(genericDecl, Adoptee, - SourceLoc(), DC)) { - continue; - } + auto *genericDecl = cast(typeDecl); + + // If the declaration has generic parameters, it cannot witness an + // associated type. + if (genericDecl->isGeneric()) + continue; + + // As a narrow fix for a source compatibility issue with SwiftUI's + // swiftinterface, allow the conformance if the underlying type of + // the typealias is Never. + // + // FIXME: This should be conditionalized on a new language version. + bool skipRequirementCheck = false; + if (auto *typeAliasDecl = dyn_cast(typeDecl)) { + if (typeAliasDecl->getUnderlyingType()->isUninhabited()) + skipRequirementCheck = true; } // Skip typealiases with an unbound generic type as their underlying type. - if (auto *typeAliasDecl = dyn_cast(candidate.Member)) + if (auto *typeAliasDecl = dyn_cast(typeDecl)) if (typeAliasDecl->getDeclaredInterfaceType()->is()) continue; + // Skip dependent protocol typealiases. + // + // FIXME: This should not be necessary. + if (auto *typeAliasDecl = dyn_cast(typeDecl)) { + if (isa(typeAliasDecl->getDeclContext()) && + typeAliasDecl->getUnderlyingType()->getCanonicalType() + ->hasTypeParameter()) { + continue; + } + } + + // If the type comes from a constrained extension or has a 'where' + // clause, check those requirements now. + if (!skipRequirementCheck && + !TypeChecker::checkContextualRequirements(genericDecl, Adoptee, + SourceLoc(), DC)) { + continue; + } + + auto memberType = TypeChecker::substMemberTypeWithBase(DC->getParentModule(), + typeDecl, Adoptee); + + if (!viableTypes.insert(memberType->getCanonicalType()).second) + continue; + // Check this type against the protocol requirements. if (auto checkResult = - checkTypeWitness(candidate.MemberType, assocType, Conformance)) { - nonViable.push_back({candidate.Member, checkResult}); + checkTypeWitness(memberType, assocType, Conformance)) { + nonViable.push_back({typeDecl, checkResult}); } else { - viable.push_back(candidate); + viable.push_back({typeDecl, memberType, nullptr}); } } From 1dc47970c1998c4483be66b87141166dfce2cfe5 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 17 Aug 2020 00:55:45 -0400 Subject: [PATCH 208/663] Sema: Refactor conformance checking to use lookupQualified() instead of lookupMember() TypeChecker::lookupMember() maps protocol requirements to witnesses, which we disable here by clearing NameLookupFlags::PerformConformanceCheck. Instead, let's call lookupQualified() directly, since lookupMember() doesn't add any value in this case. --- lib/Sema/TypeCheckProtocol.cpp | 78 ++++++++++++++++--------- lib/Sema/TypeCheckProtocolInference.cpp | 16 +++-- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index bac55fa09978c..83f8444d64122 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1105,16 +1105,25 @@ WitnessChecker::WitnessChecker(ASTContext &ctx, ProtocolDecl *proto, void WitnessChecker::lookupValueWitnessesViaImplementsAttr( ValueDecl *req, SmallVector &witnesses) { - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - lookupOptions |= NameLookupFlags::IncludeAttributeImplements; - auto candidates = TypeChecker::lookupMember(DC, Adoptee, req->createNameRef(), - lookupOptions); - for (auto candidate : candidates) { - if (witnessHasImplementsAttrForExactRequirement(candidate.getValueDecl(), req)) { - witnesses.push_back(candidate.getValueDecl()); - } + + auto name = req->createNameRef(); + auto *nominal = Adoptee->getAnyNominal(); + + NLOptions subOptions = (NL_ProtocolMembers | NL_IncludeAttributeImplements); + + nominal->synthesizeSemanticMembersIfNeeded(name.getFullName()); + + SmallVector lookupResults; + DC->lookupQualified(nominal, name, subOptions, lookupResults); + + for (auto decl : lookupResults) { + if (!isa(decl->getDeclContext())) + if (witnessHasImplementsAttrForExactRequirement(decl, req)) + witnesses.push_back(decl); } + + removeOverriddenDecls(witnesses); + removeShadowedDecls(witnesses, DC); } SmallVector @@ -1147,23 +1156,34 @@ WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) { } } else { // Variable/function/subscript requirements. - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - - auto candidates = TypeChecker::lookupMember(DC, Adoptee, reqName, - lookupOptions); + auto *nominal = Adoptee->getAnyNominal(); + nominal->synthesizeSemanticMembersIfNeeded(reqName.getFullName()); + + SmallVector lookupResults; + bool addedAny = false; + DC->lookupQualified(nominal, reqName, NL_ProtocolMembers, lookupResults); + for (auto *decl : lookupResults) { + if (!isa(decl->getDeclContext())) { + witnesses.push_back(decl); + addedAny = true; + } + }; // If we didn't find anything with the appropriate name, look // again using only the base name. - if (candidates.empty() && ignoringNames) { - candidates = TypeChecker::lookupMember(DC, Adoptee, reqBaseName, - lookupOptions); + if (!addedAny && ignoringNames) { + lookupResults.clear(); + DC->lookupQualified(nominal, reqBaseName, NL_ProtocolMembers, lookupResults); + for (auto *decl : lookupResults) { + if (!isa(decl->getDeclContext())) + witnesses.push_back(decl); + } + *ignoringNames = true; } - for (auto candidate : candidates) { - witnesses.push_back(candidate.getValueDecl()); - } + removeOverriddenDecls(witnesses); + removeShadowedDecls(witnesses, DC); } return witnesses; @@ -5121,16 +5141,20 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { static bool hasValidMethod(NominalTypeDecl *typeDecl, SmallVectorImpl &invalid) { - auto type = typeDecl->getDeclaredType(); + NLOptions subOptions = NL_QualifiedDefault; + subOptions |= NL_ProtocolMembers; + DeclNameRef baseName(typeDecl->getASTContext().Id_appendInterpolation); - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - for (auto resultEntry : - TypeChecker::lookupMember(typeDecl, type, baseName, lookupOptions)) { - auto method = dyn_cast(resultEntry.getValueDecl()); + SmallVector lookupResults; + typeDecl->lookupQualified(typeDecl, baseName, subOptions, lookupResults); + for (auto decl : lookupResults) { + auto method = dyn_cast(decl); if (!method) continue; - + + if (isa(method->getDeclContext())) + continue; + if (method->isStatic()) { invalid.emplace_back(method, Reason::Static); continue; diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 21fe9d350ff71..a4b6621ecdd3a 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -595,15 +595,21 @@ AssociatedTypeInference::inferTypeWitnessesViaAssociatedType( defaultName = DeclNameRef(getASTContext().getIdentifier(defaultNameStr)); } + NLOptions subOptions = (NL_QualifiedDefault | + NL_OnlyTypes | + NL_ProtocolMembers); + // Look for types with the given default name that have appropriate // @_implements attributes. + SmallVector lookupResults; + dc->lookupQualified(adoptee->getAnyNominal(), defaultName, + subOptions, lookupResults); + InferredAssociatedTypesByWitnesses result; - auto lookupOptions = defaultMemberTypeLookupOptions; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - for (auto candidate : - TypeChecker::lookupMember(dc, adoptee, defaultName, lookupOptions)) { + + for (auto decl : lookupResults) { // We want type declarations. - auto typeDecl = dyn_cast(candidate.getValueDecl()); + auto typeDecl = dyn_cast(decl); if (!typeDecl || isa(typeDecl)) continue; From 397e36a6f0e16f14ce5932c1f00c48607aab866a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 17 Aug 2020 16:54:24 -0400 Subject: [PATCH 209/663] Sema: Remove TypeChecker::lookupConstructor() --- lib/Sema/CodeSynthesis.cpp | 25 +++++++++++++------------ lib/Sema/MiscDiagnostics.cpp | 4 ++-- lib/Sema/TypeCheckNameLookup.cpp | 5 ----- lib/Sema/TypeCheckStmt.cpp | 28 +++++++++++++++------------- lib/Sema/TypeChecker.h | 11 ----------- 5 files changed, 30 insertions(+), 43 deletions(-) diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 4ff16a78a5ede..5ed7bdafa5de6 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -911,8 +911,8 @@ static bool canInheritDesignatedInits(Evaluator &eval, ClassDecl *decl) { static void collectNonOveriddenSuperclassInits( ClassDecl *subclass, SmallVectorImpl &results) { - auto superclassTy = subclass->getSuperclass(); - assert(superclassTy); + auto *superclassDecl = subclass->getSuperclassDecl(); + assert(superclassDecl); // Record all of the initializers the subclass has overriden, excluding stub // overrides, which we don't want to consider as viable delegates for @@ -924,11 +924,17 @@ static void collectNonOveriddenSuperclassInits( if (auto overridden = ctor->getOverriddenDecl()) overriddenInits.insert(overridden); - auto superclassCtors = TypeChecker::lookupConstructors( - subclass, superclassTy, NameLookupFlags::IgnoreAccessControl); + superclassDecl->synthesizeSemanticMembersIfNeeded( + DeclBaseName::createConstructor()); - for (auto memberResult : superclassCtors) { - auto superclassCtor = cast(memberResult.getValueDecl()); + NLOptions subOptions = (NL_QualifiedDefault | NL_IgnoreAccessControl); + SmallVector lookupResults; + subclass->lookupQualified( + superclassDecl, DeclNameRef::createConstructor(), + subOptions, lookupResults); + + for (auto decl : lookupResults) { + auto superclassCtor = cast(decl); // Skip invalid superclass initializers. if (superclassCtor->isInvalid()) @@ -958,12 +964,7 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) { decl->setAddedImplicitInitializers(); // We can only inherit initializers if we have a superclass. - // FIXME: We should be bailing out earlier in the function, but unfortunately - // that currently regresses associated type inference for cases like - // compiler_crashers_2_fixed/0124-sr5825.swift due to the fact that we no - // longer eagerly compute the interface types of the other constructors. - auto superclassTy = decl->getSuperclass(); - if (!superclassTy) + if (!decl->getSuperclassDecl() || !decl->getSuperclass()) return; // Check whether the user has defined a designated initializer for this class, diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 563f281663182..3965bb5375d1f 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -594,8 +594,8 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, isExistential = instanceTy->isExistentialType(); if (!isExistential && instanceTy->mayHaveMembers() && - !TypeChecker::lookupConstructors(const_cast(DC), - instanceTy).empty()) { + !TypeChecker::lookupMember(const_cast(DC), instanceTy, + DeclNameRef::createConstructor()).empty()) { Ctx.Diags.diagnose(E->getEndLoc(), diag::add_parens_to_type) .fixItInsertAfter(E->getEndLoc(), "()"); } diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 6068b1a2c527f..75a3865024af9 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -511,11 +511,6 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, return result; } -LookupResult TypeChecker::lookupConstructors(DeclContext *dc, Type type, - NameLookupOptions options) { - return lookupMember(dc, type, DeclNameRef::createConstructor(), options); -} - unsigned TypeChecker::getCallEditDistance(DeclNameRef writtenName, DeclName correctedName, unsigned maxEditDistance) { diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 9b8af8759bab2..ae47c047fc422 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1754,19 +1754,21 @@ static bool checkSuperInit(ConstructorDecl *fromCtor, // For an implicitly generated super.init() call, make sure there's // only one designated initializer. if (implicitlyGenerated) { - auto superclassTy = ctor->getDeclContext()->getDeclaredInterfaceType(); - auto lookupOptions = defaultConstructorLookupOptions; - lookupOptions |= NameLookupFlags::KnownPrivate; - - // If a constructor is only visible as a witness for a protocol - // requirement, it must be an invalid override. Also, protocol - // extensions cannot yet define designated initializers. - lookupOptions -= NameLookupFlags::ProtocolMembers; - lookupOptions -= NameLookupFlags::PerformConformanceCheck; - - for (auto member : TypeChecker::lookupConstructors(fromCtor, superclassTy, - lookupOptions)) { - auto superclassCtor = dyn_cast(member.getValueDecl()); + auto *dc = ctor->getDeclContext(); + auto *superclassDecl = dc->getSelfClassDecl(); + + superclassDecl->synthesizeSemanticMembersIfNeeded( + DeclBaseName::createConstructor()); + + NLOptions subOptions = NL_QualifiedDefault | NL_KnownNonCascadingDependency; + + SmallVector lookupResults; + dc->lookupQualified(superclassDecl, + DeclNameRef::createConstructor(), + subOptions, lookupResults); + + for (auto decl : lookupResults) { + auto superclassCtor = dyn_cast(decl); if (!superclassCtor || !superclassCtor->isDesignatedInit() || superclassCtor == ctor) continue; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 9ad183c60bc67..d39f3b150b41c 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -941,17 +941,6 @@ LookupTypeResult lookupMemberType(DeclContext *dc, Type type, DeclNameRef name, NameLookupOptions options = defaultMemberTypeLookupOptions); -/// Look up the constructors of the given type. -/// -/// \param dc The context that needs the constructor. -/// \param type The type for which we will look for constructors. -/// \param options Options that control name lookup. -/// -/// \returns the constructors found for this type. -LookupResult lookupConstructors( - DeclContext *dc, Type type, - NameLookupOptions options = defaultConstructorLookupOptions); - /// Given an expression that's known to be an infix operator, /// look up its precedence group. PrecedenceGroupDecl *lookupPrecedenceGroupForInfixOperator(DeclContext *dc, From ec4c17aeed019882683246570c973a30f442011a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 17 Aug 2020 17:04:36 -0400 Subject: [PATCH 210/663] Sema: Remove NameLookupFlags::PerformConformanceCheck --- lib/Sema/TypeCheckNameLookup.cpp | 19 +------------------ lib/Sema/TypeChecker.h | 20 ++++---------------- 2 files changed, 5 insertions(+), 34 deletions(-) diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 75a3865024af9..f7b927fceadb0 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -124,9 +124,6 @@ namespace { assert(isa(foundDC)); - if (!Options.contains(NameLookupFlags::PerformConformanceCheck)) - return; - // If we found something within the protocol itself, and our // search began somewhere that is not in a protocol or extension // thereof, remap this declaration to the witness. @@ -434,21 +431,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, if (auto assocType = dyn_cast(typeDecl)) { if (!type->is() && !type->isTypeParameter()) { - if (options.contains(NameLookupFlags::PerformConformanceCheck)) - inferredAssociatedTypes.push_back(assocType); - continue; - } - } - - // FIXME: This is a hack, we should be able to remove this entire 'if' - // statement once we learn how to deal with the circularity here. - if (auto *aliasDecl = dyn_cast(typeDecl)) { - if (isa(aliasDecl->getDeclContext()) && - !type->is() && - !type->isTypeParameter() && - aliasDecl->getUnderlyingType()->getCanonicalType() - ->hasTypeParameter() && - !options.contains(NameLookupFlags::PerformConformanceCheck)) { + inferredAssociatedTypes.push_back(assocType); continue; } } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index d39f3b150b41c..dca908de79be7 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -190,14 +190,6 @@ enum class NameLookupFlags { KnownPrivate = 0x01, /// Whether name lookup should be able to find protocol members. ProtocolMembers = 0x02, - /// Whether we should map the requirement to the witness if we - /// find a protocol member and the base type is a concrete type. - /// - /// If this is not set but ProtocolMembers is set, we will - /// find protocol extension members, but not protocol requirements - /// that do not yet have a witness (such as inferred associated - /// types, or witnesses for derived conformances). - PerformConformanceCheck = 0x04, /// Whether to perform 'dynamic' name lookup that finds @objc /// members of any class or protocol. DynamicLookup = 0x08, @@ -221,23 +213,19 @@ inline NameLookupOptions operator|(NameLookupFlags flag1, /// Default options for member name lookup. const NameLookupOptions defaultMemberLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; + = NameLookupFlags::ProtocolMembers; /// Default options for constructor lookup. const NameLookupOptions defaultConstructorLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; + = NameLookupFlags::ProtocolMembers; /// Default options for member type lookup. const NameLookupOptions defaultMemberTypeLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; + = NameLookupFlags::ProtocolMembers; /// Default options for unqualified name lookup. const NameLookupOptions defaultUnqualifiedLookupOptions - = NameLookupFlags::ProtocolMembers | - NameLookupFlags::PerformConformanceCheck; + = NameLookupFlags::ProtocolMembers; /// Describes the result of comparing two entities, of which one may be better /// or worse than the other, or they are unordered. From 6c15aad32cdb27fa03a69ab6d9c1d391aed7c9f2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 17 Aug 2020 17:08:43 -0400 Subject: [PATCH 211/663] Sema: Remove NameLookupFlags::IncludeAttributeImplements --- lib/Sema/TypeCheckNameLookup.cpp | 3 --- lib/Sema/TypeChecker.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index f7b927fceadb0..8b781cb69f9bc 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -308,9 +308,6 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; - if (options.contains(NameLookupFlags::IncludeAttributeImplements)) - subOptions |= NL_IncludeAttributeImplements; - // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index dca908de79be7..b517e23a29627 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -199,8 +199,6 @@ enum class NameLookupFlags { /// Whether to include results from outside the innermost scope that has a /// result. IncludeOuterResults = 0x20, - /// Whether to consider synonyms declared through @_implements(). - IncludeAttributeImplements = 0x40, }; /// A set of options that control name lookup. From 3372b7153dae6517b650926e756e923884a47926 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 17 Aug 2020 17:09:26 -0400 Subject: [PATCH 212/663] Sema: Remove NameLookupFlags::DynamicLookup --- lib/Sema/TypeChecker.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index b517e23a29627..bc65329d98840 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -190,9 +190,6 @@ enum class NameLookupFlags { KnownPrivate = 0x01, /// Whether name lookup should be able to find protocol members. ProtocolMembers = 0x02, - /// Whether to perform 'dynamic' name lookup that finds @objc - /// members of any class or protocol. - DynamicLookup = 0x08, /// Whether to ignore access control for this lookup, allowing inaccessible /// results to be returned. IgnoreAccessControl = 0x10, From b26abf78c2bd9e5598b40f302f2e3f47a12c9560 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 17 Aug 2020 17:15:00 -0400 Subject: [PATCH 213/663] Sema: Remove NameLookupFlags::ProtocolMembers --- lib/Sema/TypeCheckDeclPrimary.cpp | 3 +-- lib/Sema/TypeCheckNameLookup.cpp | 19 +++++-------------- lib/Sema/TypeCheckType.cpp | 4 +--- lib/Sema/TypeChecker.h | 15 +++------------ 4 files changed, 10 insertions(+), 31 deletions(-) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 7c4881e8d2305..c580185e95217 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1136,8 +1136,7 @@ static void diagnoseClassWithoutInitializers(ClassDecl *classDecl) { { C, DeclBaseName::createConstructor(), { C.Id_from } }); auto result = TypeChecker::lookupMember(superclassDecl, superclassType, initFrom, - NameLookupFlags::ProtocolMembers | - NameLookupFlags::IgnoreAccessControl); + NameLookupFlags::IgnoreAccessControl); if (!result.empty() && !result.front().getValueDecl()->isImplicit()) diagDest = result.front().getValueDecl(); diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 8b781cb69f9bc..46eb592abd1e2 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -113,8 +113,7 @@ namespace { // If this isn't a protocol member to be given special // treatment, just add the result. - if (!Options.contains(NameLookupFlags::ProtocolMembers) || - !isa(foundDC) || + if (!isa(foundDC) || isa(found) || isa(found) || (isa(found) && cast(found)->isOperator())) { @@ -207,11 +206,9 @@ namespace { static UnqualifiedLookupOptions convertToUnqualifiedLookupOptions(NameLookupOptions options) { - UnqualifiedLookupOptions newOptions; + UnqualifiedLookupOptions newOptions = UnqualifiedLookupFlags::AllowProtocolMembers; if (options.contains(NameLookupFlags::KnownPrivate)) newOptions |= UnqualifiedLookupFlags::KnownPrivate; - if (options.contains(NameLookupFlags::ProtocolMembers)) - newOptions |= UnqualifiedLookupFlags::AllowProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessControl)) newOptions |= UnqualifiedLookupFlags::IgnoreAccessControl; if (options.contains(NameLookupFlags::IncludeOuterResults)) @@ -275,8 +272,7 @@ TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclNameRef name, auto lookup = evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {}); - if (!lookup.allResults().empty() || - !options.contains(NameLookupFlags::ProtocolMembers)) + if (!lookup.allResults().empty()) return lookup; } @@ -299,15 +295,12 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, assert(type->mayHaveMembers()); LookupResult result; - NLOptions subOptions = NL_QualifiedDefault; + NLOptions subOptions = (NL_QualifiedDefault | NL_ProtocolMembers); if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::IgnoreAccessControl)) subOptions |= NL_IgnoreAccessControl; - if (options.contains(NameLookupFlags::ProtocolMembers)) - subOptions |= NL_ProtocolMembers; - // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; @@ -381,12 +374,10 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, // Look for members with the given name. SmallVector decls; - NLOptions subOptions = NL_QualifiedDefault | NL_OnlyTypes; + NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers); if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; - if (options.contains(NameLookupFlags::ProtocolMembers)) - subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessControl)) subOptions |= NL_IgnoreAccessControl; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index aacf189a1558a..2cd63edbe1563 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -197,7 +197,7 @@ Type TypeResolution::resolveDependentMemberType( TypoCorrectionResults corrections(ref->getNameRef(), ref->getNameLoc()); TypeChecker::performTypoCorrection(DC, DeclRefKind::Ordinary, MetatypeType::get(baseTy), - NameLookupFlags::ProtocolMembers, + defaultMemberLookupOptions, corrections, builder); // Check whether we have a single type result. @@ -1499,8 +1499,6 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution, NameLookupOptions lookupOptions = defaultMemberLookupOptions; if (isKnownNonCascading) lookupOptions |= NameLookupFlags::KnownPrivate; - if (options.is(TypeResolverContext::ExtensionBinding)) - lookupOptions -= NameLookupFlags::ProtocolMembers; LookupTypeResult memberTypes; if (parentTy->mayHaveMembers()) memberTypes = TypeChecker::lookupMemberType(DC, parentTy, diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index bc65329d98840..e2a95f18227af 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -188,8 +188,6 @@ inline TypeCheckExprOptions operator|(TypeCheckExprFlags flag1, enum class NameLookupFlags { /// Whether we know that this lookup is always a private dependency. KnownPrivate = 0x01, - /// Whether name lookup should be able to find protocol members. - ProtocolMembers = 0x02, /// Whether to ignore access control for this lookup, allowing inaccessible /// results to be returned. IgnoreAccessControl = 0x10, @@ -207,20 +205,13 @@ inline NameLookupOptions operator|(NameLookupFlags flag1, } /// Default options for member name lookup. -const NameLookupOptions defaultMemberLookupOptions - = NameLookupFlags::ProtocolMembers; - -/// Default options for constructor lookup. -const NameLookupOptions defaultConstructorLookupOptions - = NameLookupFlags::ProtocolMembers; +const NameLookupOptions defaultMemberLookupOptions; /// Default options for member type lookup. -const NameLookupOptions defaultMemberTypeLookupOptions - = NameLookupFlags::ProtocolMembers; +const NameLookupOptions defaultMemberTypeLookupOptions; /// Default options for unqualified name lookup. -const NameLookupOptions defaultUnqualifiedLookupOptions - = NameLookupFlags::ProtocolMembers; +const NameLookupOptions defaultUnqualifiedLookupOptions; /// Describes the result of comparing two entities, of which one may be better /// or worse than the other, or they are unordered. From b482de01c0807c7429c939479e6c9c811063bed3 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Tue, 18 Aug 2020 08:51:48 +0200 Subject: [PATCH 214/663] [Localization] Mirror the messages' changes in `.def` files --- localization/diagnostics/en.yaml | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index b4dfdad00c661..d469f67329008 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -5882,7 +5882,7 @@ msg: "call is 'async' but is not marked with 'await'" - id: async_call_without_await_in_autoclosure - msg: "call is 'async' in an autoclosure argument is not marked with 'await'" + msg: "call is 'async' in an autoclosure argument that is not marked with 'await'" - id: no_async_in_await msg: "no calls to 'async' functions occur within 'await' expression" @@ -5899,6 +5899,9 @@ - id: note_add_async_to_function msg: "add 'async' to function %0 to make it asynchronous" +- id: note_add_asynchandler_to_function + msg: "add '@asyncHandler' to function %0 to create an implicit asynchronous context" + - id: not_objc_function_async msg: "'async' function cannot be represented in Objective-C" @@ -5911,6 +5914,27 @@ - id: async_autoclosure_nonasync_function msg: "'async' autoclosure parameter in a non-'async' function" +- id: asynchandler_attr_requires_concurrency + msg: "'@asyncHandler' is only valid when experimental concurrency is enabled" + +- id: asynchandler_non_func + msg: "'@asyncHandler' can only be applied to functions" + +- id: asynchandler_returns_value + msg: "'@asyncHandler' function can only return 'Void'" + +- id: asynchandler_throws + msg: "'@asyncHandler' function cannot throw" + +- id: asynchandler_async + msg: "'@asyncHandler' function cannot be 'async' itself" + +- id: asynchandler_inout_parameter + msg: "'inout' parameter is not allowed in '@asyncHandler' function" + +- id: asynchandler_mutating + msg: "'@asyncHandler' function cannot be 'mutating'" + - id: unsupported_recursive_struct msg: "value type %0 cannot have a stored property that recursively contains it" @@ -8277,3 +8301,4 @@ - id: enum_case_added msg: "%0 has been added as a new enum case" + From cf7c237489f71c8fba3f8d5118c79e068494db04 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 18 Aug 2020 00:41:08 -0700 Subject: [PATCH 215/663] [build-toolchain] Add support for specifying a preset file. --- utils/build-toolchain | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/utils/build-toolchain b/utils/build-toolchain index f89f30f3faf1d..91b63d14626ae 100755 --- a/utils/build-toolchain +++ b/utils/build-toolchain @@ -29,6 +29,9 @@ function usage() { echo "--distcc" echo "Build with distcc to speed up the toolchain build" echo "" + echo "--preset-file" + echo "load build-script presets from the specified file" + echo "" } RESULT_DIR=$PWD @@ -38,6 +41,7 @@ cd "$(dirname $0)/.." || exit DISTCC_FLAG= DRY_RUN= BUNDLE_PREFIX= +PRESET_FILE_FLAGS= case $(uname -s) in Darwin) SWIFT_PACKAGE=buildbot_osx_package,no_test @@ -69,6 +73,10 @@ while [ $# -ne 0 ]; do ;; --distcc) DISTCC_FLAG="--distcc" + ;; + --preset-file) + shift + PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS} --preset-file=$1" ;; -h|--help) usage @@ -115,8 +123,9 @@ SWIFT_TOOLCHAIN_DIR="/Library/Developer/Toolchains/${TOOLCHAIN_NAME}.xctoolchain SYMBOLS_PACKAGE="${RESULT_DIR}/${SYM_ARCHIVE}" DRY_RUN="${DRY_RUN}" DISTCC_FLAG="${DISTCC_FLAG}" +PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS}" -./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} --preset="${SWIFT_PACKAGE}" \ +./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} ${PRESET_FILE_FLAGS} --preset="${SWIFT_PACKAGE}" \ install_destdir="${SWIFT_INSTALL_DIR}" \ installable_package="${SWIFT_INSTALLABLE_PACKAGE}" \ install_toolchain_dir="${SWIFT_TOOLCHAIN_DIR}" \ From 479a148c2325ac58f911ab1d9df925b29a8c3d4e Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 18 Aug 2020 01:07:40 -0700 Subject: [PATCH 216/663] [build-toolchain] Add the ability to specify a prefix to prepend to the specific toolchain preset invoked. --- utils/build-toolchain | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/utils/build-toolchain b/utils/build-toolchain index 91b63d14626ae..8188482a0eb6d 100755 --- a/utils/build-toolchain +++ b/utils/build-toolchain @@ -32,6 +32,9 @@ function usage() { echo "--preset-file" echo "load build-script presets from the specified file" echo "" + echo "--preset-prefix" + echo "Customize the preset invoked by prepending a prefix" + echo "" } RESULT_DIR=$PWD @@ -42,6 +45,7 @@ DISTCC_FLAG= DRY_RUN= BUNDLE_PREFIX= PRESET_FILE_FLAGS= +PRESET_PREFIX= case $(uname -s) in Darwin) SWIFT_PACKAGE=buildbot_osx_package,no_test @@ -77,6 +81,10 @@ while [ $# -ne 0 ]; do --preset-file) shift PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS} --preset-file=$1" + ;; + --preset-prefix) + shift + PRESET_PREFIX="$1" ;; -h|--help) usage @@ -125,7 +133,7 @@ DRY_RUN="${DRY_RUN}" DISTCC_FLAG="${DISTCC_FLAG}" PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS}" -./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} ${PRESET_FILE_FLAGS} --preset="${SWIFT_PACKAGE}" \ +./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} ${PRESET_FILE_FLAGS} --preset="${PRESET_PREFIX}${SWIFT_PACKAGE}" \ install_destdir="${SWIFT_INSTALL_DIR}" \ installable_package="${SWIFT_INSTALLABLE_PACKAGE}" \ install_toolchain_dir="${SWIFT_TOOLCHAIN_DIR}" \ From f756cc154da064b4f0637b81ee1fe5369a311def Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 18 Aug 2020 01:57:23 -0700 Subject: [PATCH 217/663] [build-presets.ini] Extract out osx_package no test into a mixin so we match how presets are setup for snapshots on Linux. More importantly, it will allow for downstream projects to cascade on top of snapshot no-test scheme, ensuring that as we modify/add projects, these other downstream things will keep working. The actual change here is NFC since I just extracted the preset. --- utils/build-presets.ini | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 5854c401167bf..0bda839ae737b 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1340,14 +1340,7 @@ debug-llvm debug-swift no-swift-stdlib-assertions - -# macOS package with out test -[preset: buildbot_osx_package,no_test] -mixin-preset= - buildbot_osx_package - -dash-dash - +[preset: mixin_buildbot_osx_package,no_test] skip-test-swift skip-test-swiftpm skip-test-llbuild @@ -1362,6 +1355,12 @@ extra-cmake-options= -DCMAKE_C_FLAGS="-gline-tables-only" -DCMAKE_CXX_FLAGS="-gline-tables-only" +# macOS package with out test +[preset: buildbot_osx_package,no_test] +mixin-preset= + buildbot_osx_package + mixin_buildbot_osx_package,no_test + #===------------------------------------------------------------------------===# # LLDB build configurations # From c8e3b949ca76a620fd3e7f58111cb092f680109b Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 18 Aug 2020 09:06:34 -0700 Subject: [PATCH 218/663] build: add the temporary workaround to Swift and lldb as well Ensure that we can build with the older toolchain when building Swift and LLVM as well. --- utils/build-windows-rebranch.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/build-windows-rebranch.bat b/utils/build-windows-rebranch.bat index 98b08e8334570..30c82272f6a66 100644 --- a/utils/build-windows-rebranch.bat +++ b/utils/build-windows-rebranch.bat @@ -233,6 +233,7 @@ cmake^ -DSWIFT_PATH_TO_CMARK_SOURCE:PATH=%source_root%\cmark^ -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH=%source_root%\swift-corelibs-libdispatch^ -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -DSWIFT_INCLUDE_DOCS:BOOL=NO^ -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE:PATH=%source_root%\icu-%icu_version%\include\unicode^ -DSWIFT_WINDOWS_x86_64_ICU_UC:PATH=%source_root%\icu-%icu_version%\lib64\icuuc.lib^ @@ -292,6 +293,7 @@ cmake^ -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ -DLLDB_DISABLE_PYTHON=YES^ -DLLDB_INCLUDE_TESTS:BOOL=NO^ + -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON^ -S "%source_root%\lldb" %exitOnError% cmake --build "%build_root%\lldb" %exitOnError% From bf25a017013e4d3c87a9abbb7b8b067e1eb985b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Tue, 18 Aug 2020 09:30:08 -0700 Subject: [PATCH 219/663] Revert "[Serialization] Serialize isUserAccessible on functions" This reverts commit f523c8875459d6cd950fdbfefc6ab593ced876c0. --- lib/Serialization/Deserialization.cpp | 3 --- lib/Serialization/ModuleFormat.h | 3 +-- lib/Serialization/Serialization.cpp | 1 - .../complete_user_accessibility_helper.swift | 3 --- test/IDE/complete_user_accessible.swift | 19 ------------------- 5 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 test/IDE/Inputs/complete_user_accessibility_helper.swift delete mode 100644 test/IDE/complete_user_accessible.swift diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index b166b6c850529..ddbc8f9a513d0 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2995,7 +2995,6 @@ class DeclDeserializer { DeclID accessorStorageDeclID; bool overriddenAffectsABI, needsNewVTableEntry, isTransparent; DeclID opaqueReturnTypeID; - bool isUserAccessible; ArrayRef nameAndDependencyIDs; if (!isAccessor) { @@ -3013,7 +3012,6 @@ class DeclDeserializer { rawAccessLevel, needsNewVTableEntry, opaqueReturnTypeID, - isUserAccessible, nameAndDependencyIDs); } else { decls_block::AccessorLayout::readRecord(scratch, contextID, isImplicit, @@ -3198,7 +3196,6 @@ class DeclDeserializer { fn->setForcedStaticDispatch(hasForcedStaticDispatch); ctx.evaluator.cacheOutput(NeedsNewVTableEntryRequest{fn}, std::move(needsNewVTableEntry)); - fn->setUserAccessible(isUserAccessible); if (opaqueReturnTypeID) { ctx.evaluator.cacheOutput( diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index ffb9377b8a8ea..7a8364d7852c1 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 571; // @objc protocols get AnyObject constraint +const uint16_t SWIFTMODULE_VERSION_MINOR = 572; // revert isUserAccessible /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1307,7 +1307,6 @@ namespace decls_block { AccessLevelField, // access level BCFixed<1>, // requires a new vtable slot DeclIDField, // opaque result type decl - BCFixed<1>, // isUserAccessible? BCArray // name components, // followed by TypeID dependencies // The record is trailed by: diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 3ffbba999073a..8c5cd273a7e3b 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3437,7 +3437,6 @@ class Serializer::DeclSerializer : public DeclVisitor { rawAccessLevel, fn->needsNewVTableEntry(), S.addDeclRef(fn->getOpaqueResultTypeDecl()), - fn->isUserAccessible(), nameComponentsAndDependencies); writeGenericParams(fn->getGenericParams()); diff --git a/test/IDE/Inputs/complete_user_accessibility_helper.swift b/test/IDE/Inputs/complete_user_accessibility_helper.swift deleted file mode 100644 index 0ff5d6c417bf9..0000000000000 --- a/test/IDE/Inputs/complete_user_accessibility_helper.swift +++ /dev/null @@ -1,3 +0,0 @@ -public enum MyEnum { - case foo, bar -} diff --git a/test/IDE/complete_user_accessible.swift b/test/IDE/complete_user_accessible.swift deleted file mode 100644 index 551648d195f31..0000000000000 --- a/test/IDE/complete_user_accessible.swift +++ /dev/null @@ -1,19 +0,0 @@ -/// Check that serialized non user accessible functions are not autocompleted. -/// rdar://problem/53891642 -/// SR-7460 - -// RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module %S/Inputs/complete_user_accessibility_helper.swift -module-name helper -emit-module-path %t/helper.swiftmodule -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=USER-ACCESS -I %t | %FileCheck %s -check-prefix=USER-ACCESS - -import helper - -{ - _ = MyEnum.#^USER-ACCESS^# -// USER-ACCESS: Begin completions -// USER-ACCESS-DAG: Keyword[self]/CurrNominal: self[#MyEnum.Type#]; name=self -// USER-ACCESS-DAG: Keyword/CurrNominal: Type[#MyEnum.Type#]; name=Type -// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: foo[#MyEnum#]; name=foo -// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: bar[#MyEnum#]; name=bar -// USER-ACCESS-NOT: __derived_enum_equals -} From eff8ce4d4ba94bdd20d5ef12b8a0f323b1e35eab Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Tue, 18 Aug 2020 10:30:29 -0700 Subject: [PATCH 220/663] [test] Restrict xfail in test/Serialization/load-target-normalization.swift to asserts builds It was failing because of an assertion, so unexpectedly passing on no_asserts builds. --- test/Serialization/load-target-normalization.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Serialization/load-target-normalization.swift b/test/Serialization/load-target-normalization.swift index 6dbc31841fd78..8a013a2cefbd9 100644 --- a/test/Serialization/load-target-normalization.swift +++ b/test/Serialization/load-target-normalization.swift @@ -2,7 +2,7 @@ // RUN: touch %t/ForeignModule.swiftmodule/garbage-garbage-garbage.swiftmodule // SR-12363: This test crashes on master-next. -// XFAIL: * +// XFAIL: asserts // Test format: We try to import ForeignModule with architectures besides // garbage-garbage-garbage and check the target triple listed in the error From db18deaf91556d1baf85a257b81a320b581b51c9 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Tue, 18 Aug 2020 11:46:42 -0700 Subject: [PATCH 221/663] Add a SWIFT_RUNTIME_MACHO_NO_DYLD stdlib mode that doesn't dynamically look up sections in modules, and only assumes a single static module (#33441) --- stdlib/CMakeLists.txt | 4 + stdlib/cmake/modules/AddSwiftStdlib.cmake | 4 + stdlib/public/runtime/CMakeLists.txt | 1 + stdlib/public/runtime/Errors.cpp | 2 +- stdlib/public/runtime/ImageInspectionCommon.h | 22 +++++- .../public/runtime/ImageInspectionMachO.cpp | 33 ++++---- .../public/runtime/ImageInspectionStatic.cpp | 77 +++++++++++++++++++ utils/build-presets.ini | 1 + utils/build-script-impl | 2 + 9 files changed, 127 insertions(+), 19 deletions(-) create mode 100644 stdlib/public/runtime/ImageInspectionStatic.cpp diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index 70d45d3821c1d..2e82392b6e20a 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -17,6 +17,10 @@ option(SWIFT_ENABLE_COMPATIBILITY_OVERRIDES "Support back-deploying compatibility fixes for newer apps running on older runtimes." TRUE) +option(SWIFT_RUNTIME_MACHO_NO_DYLD + "Build stdlib assuming the runtime environment uses Mach-O but does not support dynamic modules." + FALSE) + # # End of user-configurable options. # diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index a751a1da805a0..34d5d417d42be 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -302,6 +302,10 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-DSWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES") endif() + if(SWIFT_RUNTIME_MACHO_NO_DYLD) + list(APPEND result "-DSWIFT_RUNTIME_MACHO_NO_DYLD") + endif() + set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) endfunction() diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index ed72fba6bf02d..bb5cfe990cb7e 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -50,6 +50,7 @@ set(swift_runtime_sources ImageInspectionMachO.cpp ImageInspectionELF.cpp ImageInspectionCOFF.cpp + ImageInspectionStatic.cpp KeyPaths.cpp KnownMetadata.cpp Metadata.cpp diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 6e0dd53758bc9..b5a5e467388cb 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -137,7 +137,7 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName, void swift::dumpStackTraceEntry(unsigned index, void *framePC, bool shortOutput) { -#if SWIFT_SUPPORTS_BACKTRACE_REPORTING +#if SWIFT_SUPPORTS_BACKTRACE_REPORTING && !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) SymbolInfo syminfo; // 0 is failure for lookupSymbol diff --git a/stdlib/public/runtime/ImageInspectionCommon.h b/stdlib/public/runtime/ImageInspectionCommon.h index 4166adcf1c90f..b18f9c48cdaa9 100644 --- a/stdlib/public/runtime/ImageInspectionCommon.h +++ b/stdlib/public/runtime/ImageInspectionCommon.h @@ -19,7 +19,27 @@ #ifndef SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H #define SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H -#if !defined(__MACH__) +#if defined(__MACH__) + +#include + +/// The Mach-O section name for the section containing protocol descriptor +/// references. This lives within SEG_TEXT. +#define MachOProtocolsSection "__swift5_protos" +/// The Mach-O section name for the section containing protocol conformances. +/// This lives within SEG_TEXT. +#define MachOProtocolConformancesSection "__swift5_proto" +/// The Mach-O section name for the section containing type references. +/// This lives within SEG_TEXT. +#define MachOTypeMetadataRecordSection "__swift5_types" +/// The Mach-O section name for the section containing dynamic replacements. +/// This lives within SEG_TEXT. +#define MachODynamicReplacementSection "__swift5_replace" +#define MachODynamicReplacementSomeSection "__swift5_replac2" + +#define MachOTextSegment "__TEXT" + +#else #if defined(__ELF__) #define SWIFT_REFLECTION_METADATA_ELF_NOTE_MAGIC_STRING "swift_reflection_metadata_magic_string" diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp index 643cd66589888..54c4d17a52a5e 100644 --- a/stdlib/public/runtime/ImageInspectionMachO.cpp +++ b/stdlib/public/runtime/ImageInspectionMachO.cpp @@ -18,9 +18,11 @@ /// //===----------------------------------------------------------------------===// -#if defined(__APPLE__) && defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) && \ + !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) #include "ImageInspection.h" +#include "ImageInspectionCommon.h" #include "swift/Runtime/Config.h" #include #include @@ -31,21 +33,17 @@ using namespace swift; namespace { -/// The Mach-O section name for the section containing protocol descriptor -/// references. This lives within SEG_TEXT. -constexpr const char ProtocolsSection[] = "__swift5_protos"; -/// The Mach-O section name for the section containing protocol conformances. -/// This lives within SEG_TEXT. -constexpr const char ProtocolConformancesSection[] = "__swift5_proto"; -/// The Mach-O section name for the section containing type references. -/// This lives within SEG_TEXT. -constexpr const char TypeMetadataRecordSection[] = "__swift5_types"; -/// The Mach-O section name for the section containing dynamic replacements. -/// This lives within SEG_TEXT. -constexpr const char DynamicReplacementSection[] = "__swift5_replace"; -constexpr const char DynamicReplacementSomeSection[] = "__swift5_replac2"; - -constexpr const char TextSegment[] = SEG_TEXT; + +constexpr const char ProtocolsSection[] = MachOProtocolsSection; +constexpr const char ProtocolConformancesSection[] = + MachOProtocolConformancesSection; +constexpr const char TypeMetadataRecordSection[] = + MachOTypeMetadataRecordSection; +constexpr const char DynamicReplacementSection[] = + MachODynamicReplacementSection; +constexpr const char DynamicReplacementSomeSection[] = + MachODynamicReplacementSomeSection; +constexpr const char TextSegment[] = MachOTextSegment; #if __POINTER_WIDTH__ == 64 using mach_header_platform = mach_header_64; @@ -182,4 +180,5 @@ void *swift::lookupSection(const char *segment, const char *section, size_t *out #endif // #ifndef SWIFT_RUNTIME_NO_COMPATIBILITY_OVERRIDES -#endif // defined(__APPLE__) && defined(__MACH__) +#endif // defined(__APPLE__) && defined(__MACH__) && + // !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) diff --git a/stdlib/public/runtime/ImageInspectionStatic.cpp b/stdlib/public/runtime/ImageInspectionStatic.cpp new file mode 100644 index 0000000000000..8c0d42253c61f --- /dev/null +++ b/stdlib/public/runtime/ImageInspectionStatic.cpp @@ -0,0 +1,77 @@ +//===--- ImageInspectionStatic.cpp - image inspection for static stdlib ---===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Implementation of ImageInspection for static stdlib (no dynamic loader +/// present) environments. Assumes that only a single image exists in memory. +/// +//===----------------------------------------------------------------------===// + +#if defined(__MACH__) && defined(SWIFT_RUNTIME_MACHO_NO_DYLD) + +#include "ImageInspection.h" +#include "ImageInspectionCommon.h" + +using namespace swift; + +#define GET_SECTION_START_AND_SIZE(start, size, _seg, _sec) \ + extern void *__s##_seg##_sec __asm("section$start$" _seg "$" _sec); \ + extern void *__e##_seg##_sec __asm("section$end$" _seg "$" _sec); \ + start = &__s##_seg##_sec; \ + size = (char *)&__e##_seg##_sec - (char *)&__s##_seg##_sec; + +void swift::initializeProtocolLookup() { + void *start; + uintptr_t size; + GET_SECTION_START_AND_SIZE(start, size, TextSegment, ProtocolsSection); + if (start == nullptr || size == 0) + return; + addImageProtocolsBlockCallbackUnsafe(start, size); +} + +void swift::initializeProtocolConformanceLookup() { + void *start; + uintptr_t size; + GET_SECTION_START_AND_SIZE(start, size, TextSegment, + ProtocolConformancesSection); + if (start == nullptr || size == 0) + return; + addImageProtocolConformanceBlockCallbackUnsafe(start, size); +} +void swift::initializeTypeMetadataRecordLookup() { + void *start; + uintptr_t size; + GET_SECTION_START_AND_SIZE(start, size, TextSegment, + TypeMetadataRecordSection); + if (start == nullptr || size == 0) + return; + addImageTypeMetadataRecordBlockCallbackUnsafe(start, size); +} + +void swift::initializeDynamicReplacementLookup() { + void *start1; + uintptr_t size1; + GET_SECTION_START_AND_SIZE(start1, size1, TextSegment, + DynamicReplacementSection); + if (start1 == nullptr || size1 == 0) + return; + void *start2; + uintptr_t size2; + GET_SECTION_START_AND_SIZE(start2, size2, TextSegment, + DynamicReplacementSection); + if (start2 == nullptr || size2 == 0) + return; + addImageDynamicReplacementBlockCallback(start1, size1, start2, size2); +} + +#endif // defined(__MACH__) && defined(SWIFT_RUNTIME_MACHO_NO_DYLD) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index e8231a2e9421d..ed50414e7872b 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2425,6 +2425,7 @@ build-swift-dynamic-stdlib=0 build-swift-static-stdlib=1 swift-objc-interop=0 swift-enable-compatibility-overrides=0 +swift-runtime-macho-no-dyld=1 [preset: stdlib_S_standalone_minimal_macho_x86_64,build] mixin-preset= diff --git a/utils/build-script-impl b/utils/build-script-impl index 572f6c20a00f1..6e471f191c386 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -194,6 +194,7 @@ KNOWN_SETTINGS=( stdlib-deployment-targets "" "space-separated list of targets to configure the Swift standard library to be compiled or cross-compiled for" swift-objc-interop "" "whether to enable interoperability with Objective-C, default is 1 on Apple platfors, 0 otherwise" swift-enable-compatibility-overrides "1" "whether to support back-deploying compatibility fixes for newer apps running on older runtimes" + swift-runtime-macho-no-dyld "0" "whether to build stdlib assuming the runtime environment does not support dynamic modules" ## FREESTANDING Stdlib Options swift-freestanding-sdk "" "which SDK to use when building the FREESTANDING stdlib" @@ -1762,6 +1763,7 @@ for host in "${ALL_HOSTS[@]}"; do -DSWIFT_STDLIB_USE_NONATOMIC_RC:BOOL=$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}") -DSWIFT_ENABLE_COMPATIBILITY_OVERRIDES:BOOL=$(true_false "${SWIFT_ENABLE_COMPATIBILITY_OVERRIDES}") -DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS:BOOL=$(true_false "${SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS}") + -DSWIFT_RUNTIME_MACHO_NO_DYLD:BOOL=$(true_false "${SWIFT_RUNTIME_MACHO_NO_DYLD}") -DSWIFT_NATIVE_LLVM_TOOLS_PATH:STRING="${native_llvm_tools_path}" -DSWIFT_NATIVE_CLANG_TOOLS_PATH:STRING="${native_clang_tools_path}" -DSWIFT_NATIVE_SWIFT_TOOLS_PATH:STRING="${native_swift_tools_path}" From c48eb5f0ec9a51d06148a9dbb35e2cf3de92d5cf Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Tue, 18 Aug 2020 12:33:15 -0700 Subject: [PATCH 222/663] Fix test abitypes.swift for recent i1 to i8 store change rdar://67326252 --- test/IRGen/abitypes.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/IRGen/abitypes.swift b/test/IRGen/abitypes.swift index e62790d288d3c..00b804c660a23 100644 --- a/test/IRGen/abitypes.swift +++ b/test/IRGen/abitypes.swift @@ -580,7 +580,8 @@ public func testInlineAgg(_ rect: MyRect) -> Float { // arm64-ios: [[PTR0:%.*]] = getelementptr inbounds %TSo14FiveByteStructV, %TSo14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0 // arm64-ios: [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0 // arm64-ios: [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0 -// arm64-ios: store i1 false, i1* [[PTR2]], align 8 +// arm64-ios: [[BYTE_ADDR:%.*]] = bitcast i1* [[PTR2]] to i8* +// arm64-ios: store i8 0, i8* [[BYTE_ADDR]], align 8 // arm64-ios: [[ARG:%.*]] = load i64, i64* [[COERCED]] // arm64-ios: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) // @@ -590,7 +591,8 @@ public func testInlineAgg(_ rect: MyRect) -> Float { // arm64e-ios: [[PTR0:%.*]] = getelementptr inbounds %TSo14FiveByteStructV, %TSo14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0 // arm64e-ios: [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0 // arm64e-ios: [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0 -// arm64e-ios: store i1 false, i1* [[PTR2]], align 8 +// arm64e-ios: [[BYTE_ADDR:%.*]] = bitcast i1* [[PTR2]] to i8* +// arm64e-ios: store i8 0, i8* [[BYTE_ADDR]], align 8 // arm64e-ios: [[ARG:%.*]] = load i64, i64* [[COERCED]] // arm64e-ios: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) // arm64-macosx: define swiftcc void @"$s8abitypes14testBOOLStructyyF"() @@ -599,7 +601,8 @@ public func testInlineAgg(_ rect: MyRect) -> Float { // arm64-macosx: [[PTR0:%.*]] = getelementptr inbounds %TSo14FiveByteStructV, %TSo14FiveByteStructV* [[STRUCTPTR]], {{i.*}} 0, {{i.*}} 0 // arm64-macosx: [[PTR1:%.*]] = getelementptr inbounds %T10ObjectiveC8ObjCBoolV, %T10ObjectiveC8ObjCBoolV* [[PTR0]], {{i.*}} 0, {{i.*}} 0 // arm64-macosx: [[PTR2:%.*]] = getelementptr inbounds %TSb, %TSb* [[PTR1]], {{i.*}} 0, {{i.*}} 0 -// arm64-macosx: store i1 false, i1* [[PTR2]], align 8 +// arm64-macosx: [[BYTE_ADDR:%.*]] = bitcast i1* [[PTR2]] to i8* +// arm64-macosx: store i8 0, i8* [[BYTE_ADDR]], align 8 // arm64-macosx: [[ARG:%.*]] = load i64, i64* [[COERCED]] // arm64-macosx: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*, i64)*)(i8* {{.*}}, i8* {{.*}}, i64 [[ARG]]) public func testBOOLStruct() { From 78a2460de115dfcf24482e9d5c77baa91b498168 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Tue, 11 Aug 2020 23:13:02 +0300 Subject: [PATCH 223/663] [NFC] Remove TypeLoc::setInvalidType --- include/swift/AST/TypeLoc.h | 1 - lib/AST/ASTContext.cpp | 4 ---- lib/Sema/TypeCheckDeclPrimary.cpp | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/include/swift/AST/TypeLoc.h b/include/swift/AST/TypeLoc.h index 2f8007dda9900..9cdab2c61be43 100644 --- a/include/swift/AST/TypeLoc.h +++ b/include/swift/AST/TypeLoc.h @@ -62,7 +62,6 @@ class alignas(1 << TypeReprAlignInBits) TypeLoc final { bool isNull() const { return getType().isNull() && TyR == nullptr; } - void setInvalidType(ASTContext &C); void setType(Type Ty); friend llvm::hash_code hash_value(const TypeLoc &owner) { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 10b81d3183be1..830aed2cfe57a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3886,10 +3886,6 @@ CanType OpenedArchetypeType::getAny(Type existential) { return OpenedArchetypeType::get(existential); } -void TypeLoc::setInvalidType(ASTContext &C) { - Ty = ErrorType::get(C); -} - void SubstitutionMap::Storage::Profile( llvm::FoldingSetNodeID &id, GenericSignature genericSig, diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index c580185e95217..d00d1dcc8f95c 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1851,7 +1851,7 @@ class DeclChecker : public DeclVisitor { if (!computeAutomaticEnumValueKind(ED)) { DE.diagnose(ED->getInherited().front().getSourceRange().Start, diag::raw_type_not_literal_convertible, rawTy); - ED->getInherited().front().setInvalidType(getASTContext()); + ED->getInherited().front().setType(ErrorType::get(getASTContext())); } // We need at least one case to have a raw value. From 3de97908e46734aa8962437784fca5869aef987a Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Wed, 12 Aug 2020 00:40:13 +0300 Subject: [PATCH 224/663] [NFC] Avoid passing a TypeLoc to AccessorDecl::create --- include/swift/AST/Decl.h | 2 +- lib/AST/Decl.cpp | 4 ++-- lib/ClangImporter/ImportDecl.cpp | 22 +++++++++---------- lib/Parse/ParseDecl.cpp | 5 +---- .../DerivedConformanceEquatableHashable.cpp | 2 +- lib/Sema/DerivedConformances.cpp | 4 +--- lib/Sema/TypeCheckStorage.cpp | 8 +++---- 7 files changed, 20 insertions(+), 27 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 5d1061ae9215e..b2459406d89e7 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -6410,7 +6410,7 @@ class AccessorDecl final : public FuncDecl { bool throws, SourceLoc throwsLoc, GenericParamList *genericParams, ParameterList *parameterList, - TypeLoc fnRetType, DeclContext *parent, + Type fnRetType, DeclContext *parent, ClangNode clangNode = ClangNode()); SourceLoc getAccessorKeywordLoc() const { return AccessorKeywordLoc; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2b2abaa3270d7..a149083dade69 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7249,7 +7249,7 @@ AccessorDecl *AccessorDecl::create(ASTContext &ctx, bool throws, SourceLoc throwsLoc, GenericParamList *genericParams, ParameterList * bodyParams, - TypeLoc fnRetType, + Type fnRetType, DeclContext *parent, ClangNode clangNode) { auto *D = AccessorDecl::createImpl( @@ -7257,7 +7257,7 @@ AccessorDecl *AccessorDecl::create(ASTContext &ctx, staticLoc, staticSpelling, throws, throwsLoc, genericParams, parent, clangNode); D->setParameters(bodyParams); - D->getBodyResultTypeLoc() = fnRetType; + D->getBodyResultTypeLoc() = TypeLoc::withoutLoc(fnRetType); return D; } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index a67dd74a11eca..03e724fda415d 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -163,7 +163,6 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, bool throws, DeclContext *dc, ClangNode clangNode) { - TypeLoc resultTypeLoc = resultTy ? TypeLoc::withoutLoc(resultTy) : TypeLoc(); if (accessorInfo) { return AccessorDecl::create(ctx, funcLoc, /*accessorKeywordLoc*/ SourceLoc(), @@ -175,8 +174,9 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, bodyParams, - resultTypeLoc, dc, clangNode); + resultTy, dc, clangNode); } else { + TypeLoc resultTypeLoc = resultTy ? TypeLoc::withoutLoc(resultTy) : TypeLoc(); return FuncDecl::create(ctx, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, funcLoc, name, nameLoc, @@ -611,7 +611,7 @@ static void makeEnumRawValueGetter(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(rawTy), enumDecl); + rawTy, enumDecl); getterDecl->setImplicit(); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); @@ -687,7 +687,7 @@ static AccessorDecl *makeStructRawValueGetter( /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(computedType), structDecl); + computedType, structDecl); getterDecl->setImplicit(); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); @@ -717,7 +717,7 @@ static AccessorDecl *makeFieldGetterDecl(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(getterType), importedDecl, clangNode); + getterType, importedDecl, clangNode); getterDecl->setAccess(AccessLevel::Public); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); @@ -750,7 +750,7 @@ static AccessorDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(voidTy), importedDecl, clangNode); + voidTy, importedDecl, clangNode); setterDecl->setIsObjC(false); setterDecl->setIsDynamic(false); setterDecl->setSelfAccessKind(SelfAccessKind::Mutating); @@ -1684,8 +1684,7 @@ buildSubscriptGetterDecl(ClangImporter::Implementation &Impl, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(elementTy), dc, + params, elementTy, dc, getter->getClangNode()); thunk->setAccess(getOverridableAccessLevel(dc)); @@ -1737,7 +1736,7 @@ buildSubscriptSetterDecl(ClangImporter::Implementation &Impl, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, valueIndicesPL, - TypeLoc::withoutLoc(TupleType::getEmpty(C)), dc, + TupleType::getEmpty(C), dc, setter->getClangNode()); thunk->setAccess(getOverridableAccessLevel(dc)); @@ -1922,7 +1921,7 @@ static bool addErrorDomain(NominalTypeDecl *swiftDecl, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(stringTy), swiftDecl); + stringTy, swiftDecl); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(false); @@ -8557,8 +8556,7 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(type), dc); + params, type, dc); func->setStatic(isStatic); func->setAccess(getOverridableAccessLevel(dc)); func->setIsObjC(false); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index bebab2b33438f..06cd532e380fa 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5234,9 +5234,6 @@ static AccessorDecl *createAccessorFunc(SourceLoc DeclLoc, EndLoc); } - // The typechecker will always fill this in. - TypeLoc ReturnType; - // Start the function. auto *D = AccessorDecl::create(P->Context, /*FIXME FuncLoc=*/DeclLoc, @@ -5247,7 +5244,7 @@ static AccessorDecl *createAccessorFunc(SourceLoc DeclLoc, (GenericParams ? GenericParams->clone(P->CurDeclContext) : nullptr), - ValueArg, ReturnType, + ValueArg, Type(), P->CurDeclContext); return D; diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index b77762648c7c4..a7b3f6aa6909c 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -899,7 +899,7 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) { /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(intType), parentDC); + intType, parentDC); getterDecl->setImplicit(); getterDecl->setBodySynthesizer(&deriveBodyHashable_hashValue); getterDecl->setIsTransparent(false); diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index b7204e4775e43..b3eb907ebb44b 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -430,8 +430,6 @@ DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, auto &C = property->getASTContext(); auto parentDC = property->getDeclContext(); ParameterList *params = ParameterList::createEmpty(C); - - Type propertyInterfaceType = property->getInterfaceType(); auto getterDecl = AccessorDecl::create(C, /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), @@ -439,7 +437,7 @@ DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(propertyInterfaceType), parentDC); + property->getInterfaceType(), parentDC); getterDecl->setImplicit(); getterDecl->setIsTransparent(false); diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 01c82f7583890..78c4d0b0066b8 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -1881,7 +1881,7 @@ static AccessorDecl *createGetterPrototype(AbstractStorageDecl *storage, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), genericParams, getterParams, - TypeLoc(), + Type(), storage->getDeclContext()); // If we're stealing the 'self' from a lazy initializer, set it now. @@ -1930,7 +1930,7 @@ static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), genericParams, params, - TypeLoc(), + Type(), storage->getDeclContext()); if (isMutating) @@ -2032,7 +2032,7 @@ createCoroutineAccessorPrototype(AbstractStorageDecl *storage, auto *params = buildIndexForwardingParamList(storage, {}, ctx); // Coroutine accessors always return (). - Type retTy = TupleType::getEmpty(ctx); + const Type retTy = TupleType::getEmpty(ctx); GenericParamList *genericParams = createAccessorGenericParams(storage); @@ -2041,7 +2041,7 @@ createCoroutineAccessorPrototype(AbstractStorageDecl *storage, kind, storage, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - genericParams, params, TypeLoc::withoutLoc(retTy), dc); + genericParams, params, retTy, dc); if (isMutating) accessor->setSelfAccessKind(SelfAccessKind::Mutating); From 5c9b737c89b9782365100a8bff98204684851994 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 18 Aug 2020 11:52:10 -0700 Subject: [PATCH 225/663] DependenciesScanner: prefer private Swift module interfaces if present rdar://67257185 --- include/swift/AST/ModuleLoader.h | 24 ++++++++-------- .../swift/Frontend/ModuleInterfaceLoader.h | 23 +++++++-------- lib/Frontend/ModuleInterfaceBuilder.cpp | 23 ++++++++------- lib/Frontend/ModuleInterfaceLoader.cpp | 28 ++++++++++--------- lib/Serialization/ModuleDependencyScanner.cpp | 18 +++++++----- .../module_deps_private_interface.swift | 16 +++++++++++ 6 files changed, 80 insertions(+), 52 deletions(-) create mode 100644 test/ScanDependencies/module_deps_private_interface.swift diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index 1460daf9f44c1..3660f00461f94 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -24,6 +24,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/TinyPtrVector.h" #include "swift/AST/ModuleDependencies.h" +#include namespace llvm { class FileCollector; @@ -103,17 +104,18 @@ struct SubCompilerInstanceInfo { /// Abstract interface to run an action in a sub ASTContext. struct InterfaceSubContextDelegate { - virtual bool runInSubContext(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref, - ArrayRef, StringRef)> action) = 0; - virtual bool runInSubCompilerInstance(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref action) = 0; + virtual std::error_code runInSubContext(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref, + ArrayRef, StringRef)> action) = 0; + virtual std::error_code runInSubCompilerInstance(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref action) = 0; virtual ~InterfaceSubContextDelegate() = default; }; diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 9e60d92c080fa..12546c939f5c1 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -415,17 +415,18 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate { StringRef prebuiltCachePath, bool serializeDependencyHashes, bool trackSystemDependencies); - bool runInSubContext(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref, - ArrayRef, StringRef)> action) override; - bool runInSubCompilerInstance(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref action) override; + std::error_code runInSubContext(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref, ArrayRef, + StringRef)> action) override; + std::error_code runInSubCompilerInstance(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref action) override; ~InterfaceSubContextDelegateImpl() = default; diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 4e118f04c0e5a..cf2ee7db8fe52 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -161,10 +161,10 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( llvm::RestorePrettyStackState(savedInnerPrettyStackState); }; - SubError = subASTDelegate.runInSubCompilerInstance(moduleName, - interfacePath, - OutPath, - diagnosticLoc, + SubError = (bool)subASTDelegate.runInSubCompilerInstance(moduleName, + interfacePath, + OutPath, + diagnosticLoc, [&](SubCompilerInstanceInfo &info) { auto &SubInstance = *info.Instance; auto subInvocation = SubInstance.getInvocation(); @@ -173,7 +173,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( .getModuleInterfaceLoader())->tryEmitForwardingModule(moduleName, interfacePath, CompiledCandidates, OutPath)) { - return false; + return std::error_code(); } FrontendOptions &FEOpts = subInvocation.getFrontendOptions(); const auto &InputInfo = FEOpts.InputsAndOutputs.firstInput(); @@ -208,7 +208,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( SubInstance.performSema(); if (SubInstance.getASTContext().hadError()) { LLVM_DEBUG(llvm::dbgs() << "encountered errors\n"); - return true; + return std::make_error_code(std::errc::not_supported); } SILOptions &SILOpts = subInvocation.getSILOptions(); @@ -217,7 +217,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( auto SILMod = performASTLowering(Mod, TC, SILOpts); if (!SILMod) { LLVM_DEBUG(llvm::dbgs() << "SILGen did not produce a module\n"); - return true; + return std::make_error_code(std::errc::not_supported); } // Setup the callbacks for serialization, which can occur during the @@ -237,7 +237,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( SmallVector Deps; bool serializeHashes = FEOpts.SerializeModuleInterfaceDependencyHashes; if (collectDepsForSerialization(SubInstance, Deps, serializeHashes)) { - return true; + return std::make_error_code(std::errc::not_supported); } if (ShouldSerializeDeps) SerializationOpts.Dependencies = Deps; @@ -253,9 +253,12 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( LLVM_DEBUG(llvm::dbgs() << "Running SIL processing passes\n"); if (SubInstance.performSILProcessing(SILMod.get())) { LLVM_DEBUG(llvm::dbgs() << "encountered errors\n"); - return true; + return std::make_error_code(std::errc::not_supported); + } + if (SubInstance.getDiags().hadAnyError()) { + return std::make_error_code(std::errc::not_supported); } - return SubInstance.getDiags().hadAnyError(); + return std::error_code(); }); }); return !RunSuccess || SubError; diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 7cb56c08e5301..78436cecfd086 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1393,11 +1393,12 @@ InterfaceSubContextDelegateImpl::getCacheHash(StringRef useInterfacePath) { return llvm::APInt(64, H).toString(36, /*Signed=*/false); } -bool InterfaceSubContextDelegateImpl::runInSubContext(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref, +std::error_code +InterfaceSubContextDelegateImpl::runInSubContext(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref, ArrayRef, StringRef)> action) { return runInSubCompilerInstance(moduleName, interfacePath, outputPath, diagLoc, [&](SubCompilerInstanceInfo &info){ @@ -1409,11 +1410,12 @@ bool InterfaceSubContextDelegateImpl::runInSubContext(StringRef moduleName, }); } -bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleName, - StringRef interfacePath, - StringRef outputPath, - SourceLoc diagLoc, - llvm::function_ref action) { +std::error_code +InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleName, + StringRef interfacePath, + StringRef outputPath, + SourceLoc diagLoc, + llvm::function_ref action) { // We are about to mess up the compiler invocation by using the compiler // arguments in the textual interface file. So copy to use a new compiler // invocation. @@ -1457,12 +1459,12 @@ bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleN CompilerVersion, interfacePath, diagLoc)) { - return true; + return std::make_error_code(std::errc::not_supported); } // Insert arguments collected from the interface file. BuildArgs.insert(BuildArgs.end(), SubArgs.begin(), SubArgs.end()); if (subInvocation.parseArgs(SubArgs, Diags)) { - return true; + return std::make_error_code(std::errc::not_supported); } CompilerInstance subInstance; SubCompilerInstanceInfo info; @@ -1474,7 +1476,7 @@ bool InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleN ForwardingDiagnosticConsumer FDC(Diags); subInstance.addDiagnosticConsumer(&FDC); if (subInstance.setup(subInvocation)) { - return true; + return std::make_error_code(std::errc::not_supported); } info.BuildArguments = BuildArgs; info.Hash = CacheHash; diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index d72577a2741b6..ab06b6189060f 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -81,6 +81,12 @@ class ModuleDependencyScanner : public SerializedModuleLoaderBase { } } assert(fs.exists(InPath)); + // Use the private interface file if exits. + auto PrivateInPath = + BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile); + if (fs.exists(PrivateInPath)) { + InPath = PrivateInPath; + } auto dependencies = scanInterfaceFile(InPath, IsFramework); if (dependencies) { this->dependencies = std::move(dependencies.get()); @@ -182,9 +188,8 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( llvm::SmallString<32> modulePath = moduleName.str(); llvm::sys::path::replace_extension(modulePath, newExt); Optional Result; - std::error_code code; - - auto hasError = astDelegate.runInSubContext(moduleName.str(), + std::error_code code = + astDelegate.runInSubContext(moduleName.str(), moduleInterfacePath.str(), StringRef(), SourceLoc(), @@ -205,8 +210,7 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( auto &fs = *Ctx.SourceMgr.getFileSystem(); auto interfaceBuf = fs.getBufferForFile(moduleInterfacePath); if (!interfaceBuf) { - code = interfaceBuf.getError(); - return true; + return interfaceBuf.getError(); } // Create a source file. @@ -225,10 +229,10 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( for (auto name: imInfo.ModuleNames) { Result->addModuleDependency(name.str(), &alreadyAddedModules); } - return false; + return std::error_code(); }); - if (hasError) { + if (code) { return code; } return *Result; diff --git a/test/ScanDependencies/module_deps_private_interface.swift b/test/ScanDependencies/module_deps_private_interface.swift new file mode 100644 index 0000000000000..bbf0a2dfbd053 --- /dev/null +++ b/test/ScanDependencies/module_deps_private_interface.swift @@ -0,0 +1,16 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: echo "// swift-interface-format-version: 1.0" > %t/Foo.swiftinterface +// RUN: echo "// swift-module-flags: -module-name Foo" >> %t/Foo.swiftinterface +// RUN: echo "public func foo() {}" >> %t/Foo.swiftinterface + +// RUN: cp %t/Foo.swiftinterface %t/Foo.private.swiftinterface + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json + +import Foo + +// CHECK: "moduleInterfacePath": "{{.*}}Foo.private.swiftinterface", From 17c8d2749f400610c72aad590ba4758abf77d699 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 24 Jun 2020 11:37:08 -0700 Subject: [PATCH 226/663] test: migrate tests to Python3 by default This changes the python interpreter used to invoke the tests to Python3. Python2 has been EOL'ed by the Python Software Foundation. This migration enables the Swift test suite to run with Python 3 instead. --- test/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ec8710ec76948..ede6aee79e780 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -351,7 +351,7 @@ _Block_release(void) { }\n") endif() execute_process(COMMAND - $ "-c" "import psutil" + $ "-c" "import psutil" RESULT_VARIABLE python_psutil_status TIMEOUT 1 # second ERROR_QUIET) @@ -415,7 +415,7 @@ _Block_release(void) { }\n") ${command_upload_swift_reflection_test} ${command_clean_test_results_dir} COMMAND - $ "${LIT}" + $ "${LIT}" ${LIT_ARGS} "--param" "swift_test_subset=${test_subset}" "--param" "swift_test_mode=${test_mode}" @@ -434,7 +434,7 @@ _Block_release(void) { }\n") ${command_upload_swift_reflection_test} ${command_clean_test_results_dir} COMMAND - $ "${LIT}" + $ "${LIT}" ${LIT_ARGS} "--param" "swift_test_subset=${test_subset}" "--param" "swift_test_mode=${test_mode}" From 96bcc7a22640404684403c7b5fc45cbc651f706c Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Wed, 12 Aug 2020 03:59:36 +0300 Subject: [PATCH 227/663] [NFC] FuncDecl: Replace the const version of getBodyResultTypeLoc with a TypeRepr accessor --- include/swift/AST/Decl.h | 5 ++++- lib/AST/Decl.cpp | 8 ++++---- lib/Sema/TypeCheckConcurrency.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 2 +- lib/Sema/TypeCheckDeclObjC.cpp | 5 ++--- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index b2459406d89e7..2389b6c538a0b 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -6270,7 +6270,10 @@ class FuncDecl : public AbstractFunctionDecl { SourceRange getSourceRange() const; TypeLoc &getBodyResultTypeLoc() { return FnRetType; } - const TypeLoc &getBodyResultTypeLoc() const { return FnRetType; } + TypeRepr *getResultTypeRepr() const { return FnRetType.getTypeRepr(); } + SourceRange getResultTypeSourceRange() const { + return FnRetType.getSourceRange(); + } /// Retrieve the result interface type of this function. Type getResultInterfaceType() const; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index a149083dade69..cddd990124322 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2759,7 +2759,7 @@ OpaqueReturnTypeRepr *ValueDecl::getOpaqueResultTypeRepr() const { returnRepr = VD->getTypeReprOrParentPatternTypeRepr(); } } else if (auto *FD = dyn_cast(this)) { - returnRepr = FD->getBodyResultTypeLoc().getTypeRepr(); + returnRepr = FD->getResultTypeRepr(); } else if (auto *SD = dyn_cast(this)) { returnRepr = SD->getElementTypeLoc().getTypeRepr(); } @@ -7426,9 +7426,9 @@ SourceRange FuncDecl::getSourceRange() const { if (TrailingWhereClauseSourceRange.isValid()) return { StartLoc, TrailingWhereClauseSourceRange.End }; - if (getBodyResultTypeLoc().hasLocation() && - getBodyResultTypeLoc().getSourceRange().End.isValid()) - return { StartLoc, getBodyResultTypeLoc().getSourceRange().End }; + const auto ResultTyEndLoc = getResultTypeSourceRange().End; + if (ResultTyEndLoc.isValid()) + return { StartLoc, ResultTyEndLoc }; if (hasThrows()) return { StartLoc, getThrowsLoc() }; diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index f70cc61096e13..2019e8a179bf3 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -31,7 +31,7 @@ static bool checkAsyncHandler(FuncDecl *func, bool diagnose) { if (!func->getResultInterfaceType()->isVoid()) { if (diagnose) { func->diagnose(diag::asynchandler_returns_value) - .highlight(func->getBodyResultTypeLoc().getSourceRange()); + .highlight(func->getResultTypeSourceRange()); } return true; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 9c70eafb6b891..bbf88b95b49f2 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1682,7 +1682,7 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, switch (decl->getKind()) { case DeclKind::Func: { - TyR = cast(decl)->getBodyResultTypeLoc().getTypeRepr(); + TyR = cast(decl)->getResultTypeRepr(); break; } diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index c6b98e0991863..7cd3fcd221b55 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -604,9 +604,8 @@ bool swift::isRepresentableInObjC( if (Diagnose) { AFD->diagnose(diag::objc_invalid_on_func_result_type, getObjCDiagnosticAttrKind(Reason)); - SourceRange Range = - FD->getBodyResultTypeLoc().getTypeRepr()->getSourceRange(); - diagnoseTypeNotRepresentableInObjC(FD, ResultType, Range); + diagnoseTypeNotRepresentableInObjC(FD, ResultType, + FD->getResultTypeSourceRange()); describeObjCReason(FD, Reason); } return false; From c35d84a9055bb3011c6dfb379859d926e8ebfd7f Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Wed, 12 Aug 2020 04:01:32 +0300 Subject: [PATCH 228/663] [NFC] SubscriptDecl: Replace the const version of getElementTypeLoc with a TypeRepr accessor --- include/swift/AST/Decl.h | 5 ++++- lib/AST/Decl.cpp | 2 +- lib/Sema/TypeCheckDeclObjC.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 2389b6c538a0b..ea3fe999ead6f 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5647,7 +5647,10 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { /// operation. Type getElementInterfaceType() const; TypeLoc &getElementTypeLoc() { return ElementTy; } - const TypeLoc &getElementTypeLoc() const { return ElementTy; } + TypeRepr *getElementTypeRepr() const { return ElementTy.getTypeRepr(); } + SourceRange getElementTypeSourceRange() const { + return ElementTy.getSourceRange(); + } /// Determine the kind of Objective-C subscripting this declaration /// implies. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index cddd990124322..524911881f56f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2761,7 +2761,7 @@ OpaqueReturnTypeRepr *ValueDecl::getOpaqueResultTypeRepr() const { } else if (auto *FD = dyn_cast(this)) { returnRepr = FD->getResultTypeRepr(); } else if (auto *SD = dyn_cast(this)) { - returnRepr = SD->getElementTypeLoc().getTypeRepr(); + returnRepr = SD->getElementTypeRepr(); } return dyn_cast_or_null(returnRepr); diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 7cd3fcd221b55..7e8c1d45521f8 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -927,7 +927,7 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) { if (!IndexResult) TypeRange = SD->getIndices()->getSourceRange(); else - TypeRange = SD->getElementTypeLoc().getSourceRange(); + TypeRange = SD->getElementTypeSourceRange(); SD->diagnose(diag::objc_invalid_on_subscript, getObjCDiagnosticAttrKind(Reason)) .highlight(TypeRange); From 21faa48298824bd935c1f86215e492b36a83621b Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Wed, 12 Aug 2020 19:07:04 +0300 Subject: [PATCH 229/663] Remove FuncDecl::getBodyResultTypeLoc --- include/swift/AST/Decl.h | 28 ++++++-------- include/swift/AST/TypeCheckRequests.h | 2 - lib/AST/ASTDumper.cpp | 4 +- lib/AST/ASTPrinter.cpp | 6 +-- lib/AST/ASTWalker.cpp | 2 +- lib/AST/Decl.cpp | 54 ++++++++++++++------------- lib/AST/TypeCheckRequests.cpp | 29 ++++++++------ lib/ClangImporter/ImportDecl.cpp | 23 +++++------- lib/IDE/SyntaxModel.cpp | 2 +- lib/Migrator/APIDiffMigratorPass.cpp | 17 +++------ lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/MiscDiagnostics.cpp | 2 +- lib/Sema/PCMacro.cpp | 8 ++-- lib/Sema/TypeCheckAccess.cpp | 9 +++-- lib/Sema/TypeCheckAttr.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 7 +++- lib/Sema/TypeCheckDeclOverride.cpp | 3 +- lib/Sema/TypeCheckGeneric.cpp | 2 +- lib/Sema/TypeCheckProtocol.cpp | 14 ++++--- lib/Serialization/Deserialization.cpp | 22 +++++------ 20 files changed, 119 insertions(+), 119 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index ea3fe999ead6f..4e06e2be1a7e1 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -6149,6 +6149,7 @@ class FuncDecl : public AbstractFunctionDecl { friend class AbstractFunctionDecl; friend class SelfAccessKindRequest; friend class IsStaticRequest; + friend class ResultTypeRequest; SourceLoc StaticLoc; // Location of the 'static' token or invalid. SourceLoc FuncLoc; // Location of the 'func' token. @@ -6183,6 +6184,8 @@ class FuncDecl : public AbstractFunctionDecl { Bits.FuncDecl.HasTopLevelLocalContextCaptures = false; } + void setResultInterfaceType(Type type); + private: static FuncDecl *createImpl(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -6210,14 +6213,11 @@ class FuncDecl : public AbstractFunctionDecl { public: /// Factory function only for use by deserialization. - static FuncDecl *createDeserialized(ASTContext &Context, SourceLoc StaticLoc, + static FuncDecl *createDeserialized(ASTContext &Context, StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + DeclName Name, bool Async, bool Throws, GenericParamList *GenericParams, - DeclContext *Parent); + Type FnRetType, DeclContext *Parent); static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -6272,7 +6272,6 @@ class FuncDecl : public AbstractFunctionDecl { } SourceRange getSourceRange() const; - TypeLoc &getBodyResultTypeLoc() { return FnRetType; } TypeRepr *getResultTypeRepr() const { return FnRetType.getTypeRepr(); } SourceRange getResultTypeSourceRange() const { return FnRetType.getSourceRange(); @@ -6397,15 +6396,12 @@ class AccessorDecl final : public FuncDecl { public: static AccessorDecl *createDeserialized(ASTContext &ctx, - SourceLoc declLoc, - SourceLoc accessorKeywordLoc, - AccessorKind accessorKind, - AbstractStorageDecl *storage, - SourceLoc staticLoc, - StaticSpellingKind staticSpelling, - bool throws, SourceLoc throwsLoc, - GenericParamList *genericParams, - DeclContext *parent); + AccessorKind accessorKind, + AbstractStorageDecl *storage, + StaticSpellingKind staticSpelling, + bool throws, + GenericParamList *genericParams, + Type fnRetType, DeclContext *parent); static AccessorDecl *create(ASTContext &ctx, SourceLoc declLoc, SourceLoc accessorKeywordLoc, diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index fc3572723cb6c..c73b37dd18e2b 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1449,8 +1449,6 @@ class ResultTypeRequest private: friend SimpleRequest; - TypeLoc &getResultTypeLoc() const; - // Evaluation. Type evaluate(Evaluator &evaluator, ValueDecl *decl) const; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 532790cc94f3b..d8352e9c62e2c 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1074,13 +1074,13 @@ namespace { Indent -= 2; if (auto FD = dyn_cast(D)) { - if (FD->getBodyResultTypeLoc().getTypeRepr()) { + if (FD->getResultTypeRepr()) { OS << '\n'; Indent += 2; OS.indent(Indent); PrintWithColorRAII(OS, ParenthesisColor) << '('; OS << "result\n"; - printRec(FD->getBodyResultTypeLoc().getTypeRepr()); + printRec(FD->getResultTypeRepr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; if (auto opaque = FD->getOpaqueResultTypeDecl()) { OS << '\n'; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 2d50c54be3f3d..75929ee5f0d34 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2948,8 +2948,8 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) { SourceLoc StartLoc = decl->getStartLoc(); SourceLoc EndLoc; - if (!decl->getBodyResultTypeLoc().isNull()) { - EndLoc = decl->getBodyResultTypeLoc().getSourceRange().End; + if (decl->getResultTypeRepr()) { + EndLoc = decl->getResultTypeSourceRange().End; } else { EndLoc = decl->getSignatureSourceRange().End; } @@ -2986,7 +2986,7 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { Type ResultTy = decl->getResultInterfaceType(); if (ResultTy && !ResultTy->isVoid()) { - TypeLoc ResultTyLoc = decl->getBodyResultTypeLoc(); + TypeLoc ResultTyLoc(decl->getResultTypeRepr(), ResultTy); // When printing a protocol requirement with types substituted for a // conforming class, replace occurrences of the 'Self' generic parameter diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 3641f7c807627..c0b6c00f1e9ff 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -394,7 +394,7 @@ class Traversal : public ASTVisitor(AFD)) { if (!isa(FD)) - if (auto *const TyR = FD->getBodyResultTypeLoc().getTypeRepr()) + if (auto *const TyR = FD->getResultTypeRepr()) if (doIt(TyR)) return true; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 524911881f56f..feebc50234d60 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7113,6 +7113,11 @@ void AbstractFunctionDecl::addDerivativeFunctionConfiguration( DerivativeFunctionConfigs->insert(config); } +void FuncDecl::setResultInterfaceType(Type type) { + getASTContext().evaluator.cacheOutput(ResultTypeRequest{this}, + std::move(type)); +} + FuncDecl *FuncDecl::createImpl(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -7142,18 +7147,17 @@ FuncDecl *FuncDecl::createImpl(ASTContext &Context, } FuncDecl *FuncDecl::createDeserialized(ASTContext &Context, - SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + DeclName Name, bool Async, bool Throws, GenericParamList *GenericParams, - DeclContext *Parent) { - return createImpl(Context, StaticLoc, StaticSpelling, FuncLoc, - Name, NameLoc, Async, AsyncLoc, Throws, ThrowsLoc, - GenericParams, Parent, - ClangNode()); + Type FnRetType, DeclContext *Parent) { + assert(FnRetType && "Deserialized result type must not be null"); + auto *const FD = + FuncDecl::createImpl(Context, SourceLoc(), StaticSpelling, SourceLoc(), + Name, SourceLoc(), Async, SourceLoc(), Throws, + SourceLoc(), GenericParams, Parent, ClangNode()); + FD->setResultInterfaceType(FnRetType); + return FD; } FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc, @@ -7171,7 +7175,7 @@ FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc, Name, NameLoc, Async, AsyncLoc, Throws, ThrowsLoc, GenericParams, Parent, ClangN); FD->setParameters(BodyParams); - FD->getBodyResultTypeLoc() = FnRetType; + FD->FnRetType = FnRetType; return FD; } @@ -7223,20 +7227,18 @@ AccessorDecl *AccessorDecl::createImpl(ASTContext &ctx, return D; } -AccessorDecl *AccessorDecl::createDeserialized(ASTContext &ctx, - SourceLoc declLoc, - SourceLoc accessorKeywordLoc, - AccessorKind accessorKind, - AbstractStorageDecl *storage, - SourceLoc staticLoc, - StaticSpellingKind staticSpelling, - bool throws, SourceLoc throwsLoc, - GenericParamList *genericParams, - DeclContext *parent) { - return createImpl(ctx, declLoc, accessorKeywordLoc, accessorKind, - storage, staticLoc, staticSpelling, - throws, throwsLoc, genericParams, parent, - ClangNode()); +AccessorDecl * +AccessorDecl::createDeserialized(ASTContext &ctx, AccessorKind accessorKind, + AbstractStorageDecl *storage, + StaticSpellingKind staticSpelling, + bool throws, GenericParamList *genericParams, + Type fnRetType, DeclContext *parent) { + assert(fnRetType && "Deserialized result type must not be null"); + auto *const D = AccessorDecl::createImpl( + ctx, SourceLoc(), SourceLoc(), accessorKind, storage, SourceLoc(), + staticSpelling, throws, SourceLoc(), genericParams, parent, ClangNode()); + D->setResultInterfaceType(fnRetType); + return D; } AccessorDecl *AccessorDecl::create(ASTContext &ctx, @@ -7257,7 +7259,7 @@ AccessorDecl *AccessorDecl::create(ASTContext &ctx, staticLoc, staticSpelling, throws, throwsLoc, genericParams, parent, clangNode); D->setParameters(bodyParams); - D->getBodyResultTypeLoc() = TypeLoc::withoutLoc(fnRetType); + D->setResultInterfaceType(fnRetType); return D; } diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index ff2efbc44ce89..b1458df5ec005 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -935,23 +935,28 @@ void ParamSpecifierRequest::cacheResult(ParamSpecifier specifier) const { // ResultTypeRequest computation. //----------------------------------------------------------------------------// -TypeLoc &ResultTypeRequest::getResultTypeLoc() const { - auto *decl = std::get<0>(getStorage()); - if (auto *funcDecl = dyn_cast(decl)) - return funcDecl->getBodyResultTypeLoc(); - auto *subscriptDecl = cast(decl); - return subscriptDecl->getElementTypeLoc(); -} - Optional ResultTypeRequest::getCachedResult() const { - if (auto type = getResultTypeLoc().getType()) - return type; + Type type; + auto *const decl = std::get<0>(getStorage()); + if (const auto *const funcDecl = dyn_cast(decl)) { + type = funcDecl->FnRetType.getType(); + } else { + type = cast(decl)->getElementTypeLoc().getType(); + } - return None; + if (type.isNull()) + return None; + + return type; } void ResultTypeRequest::cacheResult(Type type) const { - getResultTypeLoc().setType(type); + auto *const decl = std::get<0>(getStorage()); + if (auto *const funcDecl = dyn_cast(decl)) { + funcDecl->FnRetType.setType(type); + } else { + cast(decl)->getElementTypeLoc().setType(type); + } } //----------------------------------------------------------------------------// diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 03e724fda415d..ce04d09dcf44d 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -4417,17 +4417,6 @@ namespace { } } - auto result = createFuncOrAccessor(Impl.SwiftContext, - /*funcLoc*/SourceLoc(), - accessorInfo, - importedName.getDeclName(), - /*nameLoc*/SourceLoc(), - bodyParams, Type(), - importedName.getErrorInfo().hasValue(), - dc, decl); - - result->setAccess(getOverridableAccessLevel(dc)); - auto resultTy = importedType.getType(); auto isIUO = importedType.isImplicitlyUnwrapped(); @@ -4451,8 +4440,16 @@ namespace { } } - // Record the return type. - result->getBodyResultTypeLoc().setType(resultTy); + auto result = createFuncOrAccessor(Impl.SwiftContext, + /*funcLoc*/SourceLoc(), + accessorInfo, + importedName.getDeclName(), + /*nameLoc*/SourceLoc(), + bodyParams, resultTy, + importedName.getErrorInfo().hasValue(), + dc, decl); + + result->setAccess(getOverridableAccessLevel(dc)); // Optional methods in protocols. if (decl->getImplementationControl() == clang::ObjCMethodDecl::Optional && diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 0d06879c184a7..90a4135daf627 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -905,7 +905,7 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { AFD->getSignatureSourceRange()); if (FD) { SN.TypeRange = charSourceRangeFromSourceRange(SM, - FD->getBodyResultTypeLoc().getSourceRange()); + FD->getResultTypeSourceRange()); } pushStructureNode(SN, AFD); } else if (auto *NTD = dyn_cast(D)) { diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp index f99b28e07dc37..55d0948de6ad4 100644 --- a/lib/Migrator/APIDiffMigratorPass.cpp +++ b/lib/Migrator/APIDiffMigratorPass.cpp @@ -58,9 +58,10 @@ class ChildIndexFinder : public TypeReprVisitor { FoundResult findChild(AbstractFunctionDecl *Parent) { auto NextIndex = consumeNext(); if (!NextIndex) { - if (auto Func = dyn_cast(Parent)) - return findChild(Func->getBodyResultTypeLoc()); - if (auto Init = dyn_cast(Parent)) { + if (auto Func = dyn_cast(Parent)) { + if (auto *const TyRepr = Func->getResultTypeRepr()) + return visit(TyRepr); + } else if (auto Init = dyn_cast(Parent)) { SourceLoc End = Init->getFailabilityLoc(); bool Optional = End.isValid(); if (!Optional) @@ -73,7 +74,7 @@ class ChildIndexFinder : public TypeReprVisitor { for (auto *Param: *Parent->getParameters()) { if (!--NextIndex) { - return findChild(Param->getTypeRepr()); + return visit(Param->getTypeRepr()); } } llvm_unreachable("child index out of bounds"); @@ -100,12 +101,6 @@ class ChildIndexFinder : public TypeReprVisitor { return false; } - FoundResult findChild(TypeLoc Loc) { - if (!Loc.hasLocation()) - return {SourceRange(), false, false, false}; - return visit(Loc.getTypeRepr()); - } - public: template @@ -1257,7 +1252,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { switch (DiffItem->DiffKind) { case NodeAnnotation::GetterToProperty: { auto FuncLoc = FD->getFuncLoc(); - auto ReturnTyLoc = FD->getBodyResultTypeLoc().getSourceRange().Start; + auto ReturnTyLoc = FD->getResultTypeSourceRange().Start; auto NameLoc = FD->getNameLoc(); if (FuncLoc.isInvalid() || ReturnTyLoc.isInvalid() || NameLoc.isInvalid()) break; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 80bcf26c217d0..76488f95b81eb 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -5002,7 +5002,7 @@ bool ExtraneousReturnFailure::diagnoseAsError() { // cases like like 'var foo: () { return 1 }' as here that loc will // be invalid. We also need to check that the name is not empty, // because certain decls will have empty name (like setters). - if (FD->getBodyResultTypeLoc().getLoc().isInvalid() && + if (FD->getResultTypeRepr() == nullptr && FD->getParameters()->getStartLoc().isValid() && !FD->getBaseIdentifier().empty()) { auto fixItLoc = Lexer::getLocForEndOfToken( diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 3965bb5375d1f..a2407233737d6 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -2223,7 +2223,7 @@ static bool fixItOverrideDeclarationTypesImpl( fixedAny |= checkType(resultType, ParamDecl::Specifier::Default, baseResultType, ParamDecl::Specifier::Default, - method->getBodyResultTypeLoc().getSourceRange()); + method->getResultTypeSourceRange()); } return fixedAny; } diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 0ce8b28ac54a9..573ad52e9f8f8 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -226,8 +226,8 @@ class Instrumenter : InstrumenterBase { SourceLoc StartLoc = FES->getStartLoc(); SourceLoc EndLoc = FES->getSequence()->getEndLoc(); // FIXME: get the 'end' of the for stmt - // if (FD->getBodyResultTypeLoc().hasLocation()) { - // EndLoc = FD->getBodyResultTypeLoc().getSourceRange().End; + // if (FD->getResultTypeRepr()) { + // EndLoc = FD->getResultTypeSourceRange().End; // } else { // EndLoc = FD->getParameters()->getSourceRange().End; // } @@ -343,8 +343,8 @@ class Instrumenter : InstrumenterBase { // decl at the start of the transformed body SourceLoc StartLoc = FD->getStartLoc(); SourceLoc EndLoc = SourceLoc(); - if (FD->getBodyResultTypeLoc().hasLocation()) { - EndLoc = FD->getBodyResultTypeLoc().getSourceRange().End; + if (FD->getResultTypeRepr()) { + EndLoc = FD->getResultTypeSourceRange().End; } else { EndLoc = FD->getParameters()->getSourceRange().End; } diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index e9b75ad9b5ac1..40c5cd8fdf268 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -937,7 +937,8 @@ class AccessControlChecker : public AccessControlCheckerBase, bool problemIsResult = false; if (auto FD = dyn_cast(fn)) { - checkTypeAccess(FD->getBodyResultTypeLoc(), FD, /*mayBeInferred*/false, + checkTypeAccess(FD->getResultInterfaceType(), FD->getResultTypeRepr(), + FD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr, DowngradeToWarning downgradeDiag) { @@ -1418,7 +1419,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, } if (auto FD = dyn_cast(fn)) { - checkTypeAccess(FD->getBodyResultTypeLoc(), FD, /*mayBeInferred*/false, + checkTypeAccess(FD->getResultInterfaceType(), FD->getResultTypeRepr(), + FD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeDiag) { @@ -1929,7 +1931,8 @@ class ExportabilityChecker : public DeclVisitor { void visitFuncDecl(FuncDecl *FD) { visitAbstractFunctionDecl(FD); - checkType(FD->getBodyResultTypeLoc(), FD, getDiagnoser(FD)); + checkType(FD->getResultInterfaceType(), FD->getResultTypeRepr(), FD, + getDiagnoser(FD)); } void visitEnumElementDecl(EnumElementDecl *EED) { diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 2187c52e3d15d..3e1f9d5dcf2d9 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -4786,7 +4786,7 @@ static bool typeCheckDerivativeAttr(ASTContext &Ctx, Decl *D, // Emit note with expected differential/pullback type on actual type // location. auto *tupleReturnTypeRepr = - cast(derivative->getBodyResultTypeLoc().getTypeRepr()); + cast(derivative->getResultTypeRepr()); auto *funcEltTypeRepr = tupleReturnTypeRepr->getElementType(1); diags .diagnose(funcEltTypeRepr->getStartLoc(), diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index bbf88b95b49f2..d4ed9de396824 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2003,7 +2003,12 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { } } - auto *resultTyRepr = getResultTypeLoc().getTypeRepr(); + TypeRepr *resultTyRepr = nullptr; + if (const auto *const funcDecl = dyn_cast(decl)) { + resultTyRepr = funcDecl->getResultTypeRepr(); + } else { + resultTyRepr = cast(decl)->getElementTypeRepr(); + } // Nothing to do if there's no result type. if (resultTyRepr == nullptr) diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 564e7b9ba4481..6c1c191522b74 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1169,7 +1169,8 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl, // Private migration help for overrides of Objective-C methods. TypeLoc resultTL; if (auto *methodAsFunc = dyn_cast(method)) - resultTL = methodAsFunc->getBodyResultTypeLoc(); + resultTL = TypeLoc(methodAsFunc->getResultTypeRepr(), + methodAsFunc->getResultInterfaceType()); emittedMatchError |= diagnoseMismatchedOptionals( method, method->getParameters(), resultTL, baseDecl, diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 861ee21d75350..cc9630cde50c1 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -693,7 +693,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, if (subscr) { return subscr->getElementTypeLoc().getTypeRepr(); } else if (auto *FD = dyn_cast(func)) { - return FD->getBodyResultTypeLoc().getTypeRepr(); + return FD->getResultTypeRepr(); } else { return nullptr; } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 83f8444d64122..9da506ad19f2d 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2086,7 +2086,7 @@ SourceLoc OptionalAdjustment::getOptionalityLoc(ValueDecl *witness) const { // For a function, use the result type. if (auto func = dyn_cast(witness)) { return getOptionalityLoc( - func->getBodyResultTypeLoc().getTypeRepr()); + func->getResultTypeRepr()); } // For a subscript, use the element type. @@ -5196,11 +5196,13 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { break; case InvalidMethod::Reason::ReturnType: - C.Diags - .diagnose(invalidMethod.method->getBodyResultTypeLoc().getLoc(), - diag::append_interpolation_void_or_discardable) - .fixItInsert(invalidMethod.method->getStartLoc(), - "@discardableResult "); + if (auto *const repr = invalidMethod.method->getResultTypeRepr()) { + C.Diags + .diagnose(repr->getLoc(), + diag::append_interpolation_void_or_discardable) + .fixItInsert(invalidMethod.method->getStartLoc(), + "@discardableResult "); + } break; case InvalidMethod::Reason::AccessControl: diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index ddbc8f9a513d0..2f55cde386f9d 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3123,21 +3123,19 @@ class DeclDeserializer { if (declOrOffset.isComplete()) return declOrOffset; + const auto resultType = MF.getType(resultInterfaceTypeID); + if (declOrOffset.isComplete()) + return declOrOffset; + FuncDecl *fn; if (!isAccessor) { - fn = FuncDecl::createDeserialized( - ctx, /*StaticLoc=*/SourceLoc(), staticSpelling.getValue(), - /*FuncLoc=*/SourceLoc(), name, /*NameLoc=*/SourceLoc(), - async, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/throws, /*ThrowsLoc=*/SourceLoc(), - genericParams, DC); + fn = FuncDecl::createDeserialized(ctx, staticSpelling.getValue(), name, + async, throws, genericParams, + resultType, DC); } else { auto *accessor = AccessorDecl::createDeserialized( - ctx, /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), - accessorKind, storage, - /*StaticLoc=*/SourceLoc(), staticSpelling.getValue(), - /*Throws=*/throws, /*ThrowsLoc=*/SourceLoc(), - genericParams, DC); + ctx, accessorKind, storage, staticSpelling.getValue(), + /*Throws=*/throws, genericParams, resultType, DC); accessor->setIsTransparent(isTransparent); fn = accessor; @@ -3173,8 +3171,6 @@ class DeclDeserializer { } fn->setStatic(isStatic); - - fn->getBodyResultTypeLoc().setType(MF.getType(resultInterfaceTypeID)); fn->setImplicitlyUnwrappedOptional(isIUO); ParameterList *paramList = MF.readParameterList(); From 492156c10f0b361590cb62aef85a62461a1f4b27 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Thu, 13 Aug 2020 02:06:42 +0300 Subject: [PATCH 230/663] Remove SubscriptDecl::getBodyResultTypeLoc --- include/swift/AST/Decl.h | 28 +++++++++++++-- lib/AST/ASTPrinter.cpp | 5 ++- lib/AST/ASTWalker.cpp | 2 +- lib/AST/Decl.cpp | 50 +++++++++++++++++++++++++++ lib/AST/TypeCheckRequests.cpp | 4 +-- lib/ClangImporter/ImportDecl.cpp | 14 ++++---- lib/IDE/CodeCompletion.cpp | 2 +- lib/IDE/SyntaxModel.cpp | 2 +- lib/Parse/ParseDecl.cpp | 9 ++--- lib/Sema/MiscDiagnostics.cpp | 2 +- lib/Sema/TypeCheckAccess.cpp | 9 +++-- lib/Sema/TypeCheckDecl.cpp | 4 +-- lib/Sema/TypeCheckDeclOverride.cpp | 4 ++- lib/Sema/TypeCheckGeneric.cpp | 2 +- lib/Sema/TypeCheckProtocol.cpp | 3 +- lib/Serialization/Deserialization.cpp | 13 ++++--- 16 files changed, 114 insertions(+), 39 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 4e06e2be1a7e1..f9576ee6051a3 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5598,13 +5598,16 @@ enum class ObjCSubscriptKind { /// signatures (indices and element type) are distinct. /// class SubscriptDecl : public GenericContext, public AbstractStorageDecl { + friend class ResultTypeRequest; + SourceLoc StaticLoc; SourceLoc ArrowLoc; SourceLoc EndLoc; ParameterList *Indices; TypeLoc ElementTy; -public: + void setElementInterfaceType(Type type); + SubscriptDecl(DeclName Name, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc SubscriptLoc, ParameterList *Indices, @@ -5620,6 +5623,27 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { Bits.SubscriptDecl.StaticSpelling = static_cast(StaticSpelling); setIndices(Indices); } + +public: + /// Factory function only for use by deserialization. + static SubscriptDecl *createDeserialized(ASTContext &Context, DeclName Name, + StaticSpellingKind StaticSpelling, + Type ElementTy, DeclContext *Parent, + GenericParamList *GenericParams); + + static SubscriptDecl *create(ASTContext &Context, DeclName Name, + SourceLoc StaticLoc, + StaticSpellingKind StaticSpelling, + SourceLoc SubscriptLoc, ParameterList *Indices, + SourceLoc ArrowLoc, TypeLoc ElementTy, + DeclContext *Parent, + GenericParamList *GenericParams); + + static SubscriptDecl *createImported(ASTContext &Context, DeclName Name, + SourceLoc SubscriptLoc, + ParameterList *Indices, + SourceLoc ArrowLoc, Type ElementTy, + DeclContext *Parent, ClangNode ClangN); /// \returns the way 'static'/'class' was spelled in the source. StaticSpellingKind getStaticSpelling() const { @@ -5646,7 +5670,7 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { /// Retrieve the type of the element referenced by a subscript /// operation. Type getElementInterfaceType() const; - TypeLoc &getElementTypeLoc() { return ElementTy; } + TypeRepr *getElementTypeRepr() const { return ElementTy.getTypeRepr(); } SourceRange getElementTypeSourceRange() const { return ElementTy.getSourceRange(); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 75929ee5f0d34..9423bf8506aa3 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3166,9 +3166,8 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { }); Printer << " -> "; - TypeLoc elementTy = decl->getElementTypeLoc(); - if (!elementTy.getTypeRepr()) - elementTy = TypeLoc::withoutLoc(decl->getElementInterfaceType()); + TypeLoc elementTy(decl->getElementTypeRepr(), + decl->getElementInterfaceType()); Printer.printDeclResultTypePre(decl, elementTy); Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index c0b6c00f1e9ff..c6884f049b44e 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -358,7 +358,7 @@ class Traversal : public ASTVisitorgetIndices()); - if (auto *const TyR = SD->getElementTypeLoc().getTypeRepr()) + if (auto *const TyR = SD->getElementTypeRepr()) if (doIt(TyR)) return true; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index feebc50234d60..0684206f7c3d9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6584,6 +6584,56 @@ ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const { return ObjCSubscriptKind::Keyed; } +void SubscriptDecl::setElementInterfaceType(Type type) { + getASTContext().evaluator.cacheOutput(ResultTypeRequest{this}, + std::move(type)); +} + +SubscriptDecl * +SubscriptDecl::createDeserialized(ASTContext &Context, DeclName Name, + StaticSpellingKind StaticSpelling, + Type ElementTy, DeclContext *Parent, + GenericParamList *GenericParams) { + assert(ElementTy && "Deserialized element type must not be null"); + auto *const SD = new (Context) + SubscriptDecl(Name, SourceLoc(), StaticSpelling, SourceLoc(), nullptr, + SourceLoc(), TypeLoc(), Parent, GenericParams); + SD->setElementInterfaceType(ElementTy); + return SD; +} + +SubscriptDecl *SubscriptDecl::create(ASTContext &Context, DeclName Name, + SourceLoc StaticLoc, + StaticSpellingKind StaticSpelling, + SourceLoc SubscriptLoc, + ParameterList *Indices, SourceLoc ArrowLoc, + TypeLoc ElementTy, DeclContext *Parent, + GenericParamList *GenericParams) { + auto *const SD = new (Context) + SubscriptDecl(Name, StaticLoc, StaticSpelling, SubscriptLoc, Indices, + ArrowLoc, ElementTy, Parent, GenericParams); + return SD; +} + +SubscriptDecl *SubscriptDecl::createImported(ASTContext &Context, DeclName Name, + SourceLoc SubscriptLoc, + ParameterList *Indices, + SourceLoc ArrowLoc, Type ElementTy, + DeclContext *Parent, + ClangNode ClangN) { + assert(ClangN && ElementTy); + auto *DeclPtr = allocateMemoryForDecl( + Context, sizeof(SubscriptDecl), /*includeSpaceForClangNode=*/true); + + auto *const SD = ::new (DeclPtr) + SubscriptDecl(Name, SourceLoc(), StaticSpellingKind::None, SubscriptLoc, + Indices, ArrowLoc, TypeLoc(), Parent, + /*GenericParams=*/nullptr); + SD->setElementInterfaceType(ElementTy); + SD->setClangNode(ClangN); + return SD; +} + SourceRange SubscriptDecl::getSourceRange() const { return {getSubscriptLoc(), getEndLoc()}; } diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index b1458df5ec005..82419b737dfb5 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -941,7 +941,7 @@ Optional ResultTypeRequest::getCachedResult() const { if (const auto *const funcDecl = dyn_cast(decl)) { type = funcDecl->FnRetType.getType(); } else { - type = cast(decl)->getElementTypeLoc().getType(); + type = cast(decl)->ElementTy.getType(); } if (type.isNull()) @@ -955,7 +955,7 @@ void ResultTypeRequest::cacheResult(Type type) const { if (auto *const funcDecl = dyn_cast(decl)) { funcDecl->FnRetType.setType(type); } else { - cast(decl)->getElementTypeLoc().setType(type); + cast(decl)->ElementTy.setType(type); } } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index ce04d09dcf44d..e8379d295d8fb 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -6879,12 +6879,14 @@ SwiftDeclConverter::importSubscript(Decl *decl, auto &C = Impl.SwiftContext; auto bodyParams = ParameterList::create(C, getterIndex); DeclName name(C, DeclBaseName::createSubscript(), {Identifier()}); - auto subscript = Impl.createDeclWithClangNode( - getter->getClangNode(), getOverridableAccessLevel(dc), name, - /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, - decl->getLoc(), bodyParams, decl->getLoc(), - TypeLoc::withoutLoc(elementTy), dc, - /*GenericParams=*/nullptr); + auto *const subscript = SubscriptDecl::createImported(C, + name, decl->getLoc(), + bodyParams, decl->getLoc(), + elementTy, dc, + getter->getClangNode()); + const auto access = getOverridableAccessLevel(dc); + subscript->setAccess(access); + subscript->setSetterAccess(access); // Build the thunks. AccessorDecl *getterThunk = diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index d3eb0b21c6d14..4d14814a55103 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -2387,7 +2387,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // i.e. cases where 'ExprType' != 'keyPathInfo.baseType'. auto *SD = keyPathInfo.subscript; - auto elementTy = SD->getElementTypeLoc().getType(); + const auto elementTy = SD->getElementInterfaceType(); if (!elementTy->hasTypeParameter()) return elementTy; diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 90a4135daf627..7504a1b6bf183 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -1096,7 +1096,7 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { SN.NameRange = charSourceRangeFromSourceRange(SM, SubscriptD->getSignatureSourceRange()); SN.TypeRange = charSourceRangeFromSourceRange(SM, - SubscriptD->getElementTypeLoc().getSourceRange()); + SubscriptD->getElementTypeSourceRange()); pushStructureNode(SN, SubscriptD); } else if (auto *AssociatedTypeD = dyn_cast(D)) { SyntaxStructureNode SN; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 06cd532e380fa..aa3cf8ce5cad1 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -7263,12 +7263,9 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc, // Build an AST for the subscript declaration. DeclName name = DeclName(Context, DeclBaseName::createSubscript(), argumentNames); - auto *Subscript = new (Context) SubscriptDecl(name, - StaticLoc, StaticSpelling, - SubscriptLoc, Indices.get(), - ArrowLoc, ElementTy.get(), - CurDeclContext, - GenericParams); + auto *const Subscript = SubscriptDecl::create( + Context, name, StaticLoc, StaticSpelling, SubscriptLoc, Indices.get(), + ArrowLoc, ElementTy.get(), CurDeclContext, GenericParams); Subscript->getAttrs() = Attributes; // Let the source file track the opaque return type mapping, if any. diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index a2407233737d6..f8bf7cd5219fe 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -2246,7 +2246,7 @@ static bool fixItOverrideDeclarationTypesImpl( baseSubscript->getElementInterfaceType()); fixedAny |= checkType(resultType, ParamDecl::Specifier::Default, baseResultType, ParamDecl::Specifier::Default, - subscript->getElementTypeLoc().getSourceRange()); + subscript->getElementTypeSourceRange()); return fixedAny; } diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 40c5cd8fdf268..8f2556c311a85 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -873,7 +873,8 @@ class AccessControlChecker : public AccessControlCheckerBase, }); } - checkTypeAccess(SD->getElementTypeLoc(), SD, /*mayBeInferred*/false, + checkTypeAccess(SD->getElementInterfaceType(), SD->getElementTypeRepr(), + SD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr, DowngradeToWarning downgradeDiag) { @@ -1376,7 +1377,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, }); } - checkTypeAccess(SD->getElementTypeLoc(), SD, /*mayBeInferred*/false, + checkTypeAccess(SD->getElementInterfaceType(), SD->getElementTypeRepr(), + SD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeDiag) { @@ -1918,7 +1920,8 @@ class ExportabilityChecker : public DeclVisitor { checkType(P->getInterfaceType(), P->getTypeRepr(), SD, getDiagnoser(SD)); } - checkType(SD->getElementTypeLoc(), SD, getDiagnoser(SD)); + checkType(SD->getElementInterfaceType(), SD->getElementTypeRepr(), SD, + getDiagnoser(SD)); } void visitAbstractFunctionDecl(AbstractFunctionDecl *fn) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d4ed9de396824..93c9effd91e74 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1693,14 +1693,14 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, auto *storage = accessor->getStorage(); if (auto *subscript = dyn_cast(storage)) - TyR = subscript->getElementTypeLoc().getTypeRepr(); + TyR = subscript->getElementTypeRepr(); else TyR = cast(storage)->getTypeReprOrParentPatternTypeRepr(); break; } case DeclKind::Subscript: - TyR = cast(decl)->getElementTypeLoc().getTypeRepr(); + TyR = cast(decl)->getElementTypeRepr(); break; case DeclKind::Param: { diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 6c1c191522b74..153c37ed7df83 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1198,9 +1198,11 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl, emittedMatchError = true; } else if (mayHaveMismatchedOptionals) { + TypeLoc elementTL(subscript->getElementTypeRepr(), + subscript->getElementInterfaceType()); emittedMatchError |= diagnoseMismatchedOptionals( subscript, subscript->getIndices(), - subscript->getElementTypeLoc(), baseDecl, + elementTL, baseDecl, cast(baseDecl)->getIndices(), owningTy, mayHaveMismatchedOptionals); } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index cc9630cde50c1..016345c4620bc 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -691,7 +691,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, // Gather requirements from the result type. auto *resultTypeRepr = [&subscr, &func]() -> TypeRepr * { if (subscr) { - return subscr->getElementTypeLoc().getTypeRepr(); + return subscr->getElementTypeRepr(); } else if (auto *FD = dyn_cast(func)) { return FD->getResultTypeRepr(); } else { diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 9da506ad19f2d..5c8eaf650bd10 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2091,8 +2091,7 @@ SourceLoc OptionalAdjustment::getOptionalityLoc(ValueDecl *witness) const { // For a subscript, use the element type. if (auto subscript = dyn_cast(witness)) { - return getOptionalityLoc( - subscript->getElementTypeLoc().getTypeRepr()); + return getOptionalityLoc(subscript->getElementTypeRepr()); } // Otherwise, we have a variable. diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 2f55cde386f9d..ec8645447d5b3 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3846,11 +3846,12 @@ class DeclDeserializer { if (!staticSpelling.hasValue()) MF.fatal(); - auto subscript = MF.createDecl(name, - SourceLoc(), *staticSpelling, - SourceLoc(), nullptr, - SourceLoc(), TypeLoc(), - parent, genericParams); + const auto elemInterfaceType = MF.getType(elemInterfaceTypeID); + if (declOrOffset.isComplete()) + return declOrOffset; + + auto *const subscript = SubscriptDecl::createDeserialized( + ctx, name, *staticSpelling, elemInterfaceType, parent, genericParams); subscript->setIsGetterMutating(isGetterMutating); subscript->setIsSetterMutating(isSetterMutating); declOrOffset = subscript; @@ -3874,8 +3875,6 @@ class DeclDeserializer { MF.fatal(); } - auto elemInterfaceType = MF.getType(elemInterfaceTypeID); - subscript->getElementTypeLoc().setType(elemInterfaceType); subscript->setImplicitlyUnwrappedOptional(isIUO); if (isImplicit) From f8d30ec21670c318f1e9dbfbdd02e4224f1f7c5d Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Thu, 13 Aug 2020 03:00:02 +0300 Subject: [PATCH 231/663] [NFC] SubscriptDecl: Strip factory constructors out of TypeLocs --- include/swift/AST/Decl.h | 6 +++--- lib/AST/Decl.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index f9576ee6051a3..7a34da655463e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5611,7 +5611,7 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { SubscriptDecl(DeclName Name, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc SubscriptLoc, ParameterList *Indices, - SourceLoc ArrowLoc, TypeLoc ElementTy, DeclContext *Parent, + SourceLoc ArrowLoc, TypeRepr *ElementTyR, DeclContext *Parent, GenericParamList *GenericParams) : GenericContext(DeclContextKind::SubscriptDecl, Parent, GenericParams), AbstractStorageDecl(DeclKind::Subscript, @@ -5619,7 +5619,7 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { Parent, Name, SubscriptLoc, /*will be overwritten*/ StorageIsNotMutable), StaticLoc(StaticLoc), ArrowLoc(ArrowLoc), - Indices(nullptr), ElementTy(ElementTy) { + Indices(nullptr), ElementTy(ElementTyR) { Bits.SubscriptDecl.StaticSpelling = static_cast(StaticSpelling); setIndices(Indices); } @@ -5635,7 +5635,7 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl { SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc SubscriptLoc, ParameterList *Indices, - SourceLoc ArrowLoc, TypeLoc ElementTy, + SourceLoc ArrowLoc, TypeRepr *ElementTyR, DeclContext *Parent, GenericParamList *GenericParams); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0684206f7c3d9..85509a43368b3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6597,7 +6597,7 @@ SubscriptDecl::createDeserialized(ASTContext &Context, DeclName Name, assert(ElementTy && "Deserialized element type must not be null"); auto *const SD = new (Context) SubscriptDecl(Name, SourceLoc(), StaticSpelling, SourceLoc(), nullptr, - SourceLoc(), TypeLoc(), Parent, GenericParams); + SourceLoc(), /*ElementTyR=*/nullptr, Parent, GenericParams); SD->setElementInterfaceType(ElementTy); return SD; } @@ -6607,11 +6607,12 @@ SubscriptDecl *SubscriptDecl::create(ASTContext &Context, DeclName Name, StaticSpellingKind StaticSpelling, SourceLoc SubscriptLoc, ParameterList *Indices, SourceLoc ArrowLoc, - TypeLoc ElementTy, DeclContext *Parent, + TypeRepr *ElementTyR, DeclContext *Parent, GenericParamList *GenericParams) { + assert(ElementTyR); auto *const SD = new (Context) SubscriptDecl(Name, StaticLoc, StaticSpelling, SubscriptLoc, Indices, - ArrowLoc, ElementTy, Parent, GenericParams); + ArrowLoc, ElementTyR, Parent, GenericParams); return SD; } @@ -6627,7 +6628,7 @@ SubscriptDecl *SubscriptDecl::createImported(ASTContext &Context, DeclName Name, auto *const SD = ::new (DeclPtr) SubscriptDecl(Name, SourceLoc(), StaticSpellingKind::None, SubscriptLoc, - Indices, ArrowLoc, TypeLoc(), Parent, + Indices, ArrowLoc, /*ElementTyR=*/nullptr, Parent, /*GenericParams=*/nullptr); SD->setElementInterfaceType(ElementTy); SD->setClangNode(ClangN); From efa8f86193ca934ecd939308fb7b6866467b8725 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Sat, 15 Aug 2020 22:13:27 +0300 Subject: [PATCH 232/663] [NFC] FuncDecl: Strip factory constructors out of TypeLocs --- include/swift/AST/Decl.h | 25 ++++++--- lib/AST/Builtins.cpp | 30 +++------- lib/AST/Decl.cpp | 55 ++++++++++++++----- lib/ClangImporter/ImportDecl.cpp | 11 +--- lib/Parse/ParseStmt.cpp | 20 ++----- .../DerivedConformanceAdditiveArithmetic.cpp | 14 ++--- lib/Sema/DerivedConformanceCodable.cpp | 11 ++-- lib/Sema/DerivedConformanceComparable.cpp | 16 ++---- lib/Sema/DerivedConformanceDifferentiable.cpp | 12 ++-- .../DerivedConformanceEquatableHashable.cpp | 30 ++++------ lib/Sema/TypeCheckAttr.cpp | 14 ++--- 11 files changed, 111 insertions(+), 127 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 7a34da655463e..cefb000652d63 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -6244,15 +6244,24 @@ class FuncDecl : public AbstractFunctionDecl { Type FnRetType, DeclContext *Parent); static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc, - StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + StaticSpellingKind StaticSpelling, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, bool Async, + SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, GenericParamList *GenericParams, - ParameterList *ParameterList, - TypeLoc FnRetType, DeclContext *Parent, - ClangNode ClangN = ClangNode()); + ParameterList *BodyParams, TypeRepr *ResultTyR, + DeclContext *Parent); + + static FuncDecl *createImplicit(ASTContext &Context, + StaticSpellingKind StaticSpelling, + DeclName Name, SourceLoc NameLoc, bool Async, + bool Throws, GenericParamList *GenericParams, + ParameterList *BodyParams, Type FnRetType, + DeclContext *Parent); + + static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, bool Throws, + ParameterList *BodyParams, Type FnRetType, + DeclContext *Parent, ClangNode ClangN); bool isStatic() const; diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index dde68fa9c1ea8..3a311ac116765 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -168,16 +168,10 @@ getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType) { auto *paramList = ParameterList::create(Context, params); DeclName Name(Context, Id, paramList); - auto FD = FuncDecl::create(Context, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::None, - /*FuncLoc=*/SourceLoc(), - Name, /*NameLoc=*/SourceLoc(), - /*Async-*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - paramList, - TypeLoc::withoutLoc(ResType), DC); - FD->setImplicit(); + auto *const FD = FuncDecl::createImplicit( + Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, /*Throws=*/false, + /*GenericParams=*/nullptr, paramList, ResType, DC); FD->setAccess(AccessLevel::Public); return FD; } @@ -214,17 +208,11 @@ getBuiltinGenericFunction(Identifier Id, auto *paramList = ParameterList::create(Context, params); DeclName Name(Context, Id, paramList); - auto func = FuncDecl::create(Context, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::None, - /*FuncLoc=*/SourceLoc(), - Name, /*NameLoc=*/SourceLoc(), - /*Async-*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/ Rethrows, /*ThrowsLoc=*/SourceLoc(), - GenericParams, - paramList, - TypeLoc::withoutLoc(ResType), DC); - - func->setImplicit(); + auto *const func = FuncDecl::createImplicit( + Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/Rethrows, GenericParams, paramList, ResType, DC); + func->setAccess(AccessLevel::Public); func->setGenericSignature(Sig); if (Rethrows) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 85509a43368b3..ad9f3fe3e8f6d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7212,24 +7212,51 @@ FuncDecl *FuncDecl::createDeserialized(ASTContext &Context, } FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc, - StaticSpellingKind StaticSpelling, - SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, - bool Async, SourceLoc AsyncLoc, - bool Throws, SourceLoc ThrowsLoc, + StaticSpellingKind StaticSpelling, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, bool Async, + SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, GenericParamList *GenericParams, - ParameterList *BodyParams, - TypeLoc FnRetType, DeclContext *Parent, - ClangNode ClangN) { - auto *FD = FuncDecl::createImpl( - Context, StaticLoc, StaticSpelling, FuncLoc, - Name, NameLoc, Async, AsyncLoc, Throws, ThrowsLoc, - GenericParams, Parent, ClangN); + ParameterList *BodyParams, TypeRepr *ResultTyR, + DeclContext *Parent) { + auto *const FD = FuncDecl::createImpl( + Context, StaticLoc, StaticSpelling, FuncLoc, Name, NameLoc, Async, + AsyncLoc, Throws, ThrowsLoc, GenericParams, Parent, ClangNode()); FD->setParameters(BodyParams); - FD->FnRetType = FnRetType; + FD->FnRetType = TypeLoc(ResultTyR); return FD; } - + +FuncDecl *FuncDecl::createImplicit(ASTContext &Context, + StaticSpellingKind StaticSpelling, + DeclName Name, SourceLoc NameLoc, bool Async, + bool Throws, GenericParamList *GenericParams, + ParameterList *BodyParams, Type FnRetType, + DeclContext *Parent) { + assert(FnRetType); + auto *const FD = FuncDecl::createImpl( + Context, SourceLoc(), StaticSpelling, SourceLoc(), Name, NameLoc, Async, + SourceLoc(), Throws, SourceLoc(), GenericParams, Parent, ClangNode()); + FD->setImplicit(); + FD->setParameters(BodyParams); + FD->setResultInterfaceType(FnRetType); + return FD; +} + +FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc, + DeclName Name, SourceLoc NameLoc, + bool Throws, ParameterList *BodyParams, + Type FnRetType, DeclContext *Parent, + ClangNode ClangN) { + assert(ClangN && FnRetType); + auto *const FD = FuncDecl::createImpl( + Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc, + /*Async=*/false, SourceLoc(), Throws, SourceLoc(), + /*GenericParams=*/nullptr, Parent, ClangN); + FD->setParameters(BodyParams); + FD->setResultInterfaceType(FnRetType); + return FD; +} + OperatorDecl *FuncDecl::getOperatorDecl() const { // Fast-path: Most functions are not operators. if (!isOperator()) { diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e8379d295d8fb..21488368a4dbe 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -176,15 +176,8 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, bodyParams, resultTy, dc, clangNode); } else { - TypeLoc resultTypeLoc = resultTy ? TypeLoc::withoutLoc(resultTy) : TypeLoc(); - return FuncDecl::create(ctx, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::None, - funcLoc, name, nameLoc, - /*Async=*/false, /*AsyncLoc=*/SourceLoc(), - throws, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - bodyParams, - resultTypeLoc, dc, clangNode); + return FuncDecl::createImported(ctx, funcLoc, name, nameLoc, throws, + bodyParams, resultTy, dc, clangNode); } } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index a58f435d8dc1f..e39f0daf1846b 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -943,20 +943,12 @@ ParserResult Parser::parseStmtDefer() { // closure's DeclContext. auto params = ParameterList::createEmpty(Context); DeclName name(Context, Context.getIdentifier("$defer"), params); - auto tempDecl - = FuncDecl::create(Context, - /*StaticLoc=*/ SourceLoc(), - StaticSpellingKind::None, - /*FuncLoc=*/ SourceLoc(), - name, - /*NameLoc=*/ PreviousLoc, - /*Async=*/ false, /*AsyncLoc=*/ SourceLoc(), - /*Throws=*/ false, /*ThrowsLoc=*/ SourceLoc(), - /*generic params*/ nullptr, - params, - TypeLoc(), - CurDeclContext); - tempDecl->setImplicit(); + auto *const tempDecl = FuncDecl::createImplicit( + Context, StaticSpellingKind::None, name, /*NameLoc=*/PreviousLoc, + /*Async=*/false, + /*Throws=*/false, + /*GenericParams*/ nullptr, params, TupleType::getEmpty(Context), + CurDeclContext); setLocalDiscriminator(tempDecl); ParserStatus Status; { diff --git a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp index baddb7fcfd470..353980ddde7af 100644 --- a/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp +++ b/lib/Sema/DerivedConformanceAdditiveArithmetic.cpp @@ -190,14 +190,12 @@ static ValueDecl *deriveMathOperator(DerivedConformance &derived, auto operatorId = C.getIdentifier(getMathOperatorName(op)); DeclName operatorDeclName(C, operatorId, params); - auto operatorDecl = - FuncDecl::create(C, SourceLoc(), StaticSpellingKind::KeywordStatic, - SourceLoc(), operatorDeclName, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws*/ false, SourceLoc(), - /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(selfInterfaceType), parentDC); - operatorDecl->setImplicit(); + auto *const operatorDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::KeywordStatic, operatorDeclName, + /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, selfInterfaceType, parentDC); auto bodySynthesizer = [](AbstractFunctionDecl *funcDecl, void *ctx) -> std::pair { auto op = (MathOperator) reinterpret_cast(ctx); diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 701189126dc34..f903cd126b215 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -626,12 +626,11 @@ static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) { // Func name: encode(to: Encoder) DeclName name(C, C.Id_encode, params); - auto *encodeDecl = FuncDecl::create( - C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), name, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/true, SourceLoc(), nullptr, params, - TypeLoc::withoutLoc(returnType), conformanceDC); - encodeDecl->setImplicit(); + auto *const encodeDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::None, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/true, /*GenericParams=*/nullptr, params, returnType, + conformanceDC); encodeDecl->setSynthesized(); encodeDecl->setBodySynthesizer(deriveBodyEncodable_encode); diff --git a/lib/Sema/DerivedConformanceComparable.cpp b/lib/Sema/DerivedConformanceComparable.cpp index 25be215c54351..61035b23364c1 100644 --- a/lib/Sema/DerivedConformanceComparable.cpp +++ b/lib/Sema/DerivedConformanceComparable.cpp @@ -255,17 +255,11 @@ deriveComparable_lt( } DeclName name(C, generatedIdentifier, params); - auto comparableDecl = - FuncDecl::create(C, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::KeywordStatic, - /*FuncLoc=*/SourceLoc(), name, /*NameLoc=*/SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(boolTy), - parentDC); - comparableDecl->setImplicit(); + auto *const comparableDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::KeywordStatic, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, boolTy, parentDC); comparableDecl->setUserAccessible(false); // Add the @_implements(Comparable, < (_:_:)) attribute diff --git a/lib/Sema/DerivedConformanceDifferentiable.cpp b/lib/Sema/DerivedConformanceDifferentiable.cpp index 3f7e82700574a..451dc2c65efad 100644 --- a/lib/Sema/DerivedConformanceDifferentiable.cpp +++ b/lib/Sema/DerivedConformanceDifferentiable.cpp @@ -544,15 +544,13 @@ static ValueDecl *deriveDifferentiable_method( ParameterList *params = ParameterList::create(C, {param}); DeclName declName(C, methodName, params); - auto *funcDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, - SourceLoc(), declName, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws*/ false, SourceLoc(), - /*GenericParams=*/nullptr, params, - TypeLoc::withoutLoc(returnType), parentDC); + auto *const funcDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::None, declName, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, returnType, parentDC); if (!nominal->getSelfClassDecl()) funcDecl->setSelfAccessKind(SelfAccessKind::Mutating); - funcDecl->setImplicit(); funcDecl->setBodySynthesizer(bodySynthesizer.Fn, bodySynthesizer.Context); funcDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index a7b3f6aa6909c..54d5268c52cb5 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -406,17 +406,11 @@ deriveEquatable_eq( } DeclName name(C, generatedIdentifier, params); - auto eqDecl = - FuncDecl::create(C, /*StaticLoc=*/SourceLoc(), - StaticSpellingKind::KeywordStatic, - /*FuncLoc=*/SourceLoc(), name, /*NameLoc=*/SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*GenericParams=*/nullptr, - params, - TypeLoc::withoutLoc(boolTy), - parentDC); - eqDecl->setImplicit(); + auto *const eqDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::KeywordStatic, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, boolTy, parentDC); eqDecl->setUserAccessible(false); // Add the @_implements(Equatable, ==(_:_:)) attribute @@ -549,15 +543,11 @@ deriveHashable_hashInto( // Func name: hash(into: inout Hasher) -> () DeclName name(C, C.Id_hash, params); - auto *hashDecl = FuncDecl::create(C, - SourceLoc(), StaticSpellingKind::None, - SourceLoc(), name, SourceLoc(), - /*Async*/ false, SourceLoc(), - /*Throws=*/false, SourceLoc(), - nullptr, params, - TypeLoc::withoutLoc(returnType), - parentDC); - hashDecl->setImplicit(); + auto *const hashDecl = FuncDecl::createImplicit( + C, StaticSpellingKind::None, name, /*NameLoc=*/SourceLoc(), + /*Async=*/false, + /*Throws=*/false, + /*GenericParams=*/nullptr, params, returnType, parentDC); hashDecl->setBodySynthesizer(bodySynthesizer); hashDecl->copyFormalAccessFrom(derived.Nominal); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 3e1f9d5dcf2d9..4d15582ff9f91 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1909,19 +1909,15 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator, mainFunction = viableCandidates[0]; } - auto *func = FuncDecl::create( - context, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::KeywordStatic, - /*FuncLoc*/ SourceLoc(), + auto *const func = FuncDecl::createImplicit( + context, StaticSpellingKind::KeywordStatic, DeclName(context, DeclBaseName(context.Id_MainEntryPoint), ParameterList::createEmpty(context)), - /*NameLoc*/ SourceLoc(), - /*Async*/ false, SourceLoc(), + /*NameLoc=*/SourceLoc(), + /*Async=*/false, /*Throws=*/mainFunction->hasThrows(), - /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, ParameterList::createEmpty(context), - /*FnRetType=*/TypeLoc::withoutLoc(TupleType::getEmpty(context)), - declContext); - func->setImplicit(true); + /*FnRetType=*/TupleType::getEmpty(context), declContext); func->setSynthesized(true); auto *params = context.Allocate(); From e05a7326f31f237c26f3357701bc8ca4228d51e1 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 18 Aug 2020 17:35:32 -0400 Subject: [PATCH 233/663] Sema: Fix crash-on-invalid on protocol requirements with 'where' clause constraints RequirementEnvironment wasn't prepared to handle a protocol requirement with additional 'where' clause constraints but no generic parameters. Since such a requirement necessarily runs afoul of the existing "protocol requirements cannot constrain Self" rule, it suffices to ignore such requirements when matching witnesses and let the declaration checker diagnose this situation later. Fixes . --- lib/Sema/TypeCheckProtocol.cpp | 9 ++++++++- test/decl/protocol/req/unsatisfiable.swift | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 83f8444d64122..d62c01c57b7be 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -850,7 +850,14 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache, Type openedFullWitnessType; Type reqType, openedFullReqType; - auto reqSig = req->getInnermostDeclContext()->getGenericSignatureOfContext(); + GenericSignature reqSig = proto->getGenericSignature(); + if (auto *funcDecl = dyn_cast(req)) { + if (funcDecl->isGeneric()) + reqSig = funcDecl->getGenericSignature(); + } else if (auto *subscriptDecl = dyn_cast(req)) { + if (subscriptDecl->isGeneric()) + reqSig = subscriptDecl->getGenericSignature(); + } ClassDecl *covariantSelf = nullptr; if (witness->getDeclContext()->getExtendedProtocolDecl()) { diff --git a/test/decl/protocol/req/unsatisfiable.swift b/test/decl/protocol/req/unsatisfiable.swift index 682300ddd43e4..390c856bb0950 100644 --- a/test/decl/protocol/req/unsatisfiable.swift +++ b/test/decl/protocol/req/unsatisfiable.swift @@ -58,3 +58,25 @@ protocol P4 { protocol P5 { associatedtype Y where Y : S // expected-error {{type 'Self.Y' constrained to non-protocol, non-class type 'S'}} } + +protocol P6 { + associatedtype T + associatedtype U + + func foo() where T == U + // expected-error@-1 {{instance method requirement 'foo()' cannot add constraint 'Self.T == Self.U' on 'Self'}} + // expected-note@-2 {{protocol requires function 'foo()' with type '() -> ()'; do you want to add a stub?}} +} + +struct S2 : P6 { + // expected-error@-1 {{type 'S2' does not conform to protocol 'P6'}} + typealias T = Int + typealias U = String + + func foo() {} + // expected-note@-1 {{candidate has non-matching type '() -> ()'}} + + // FIXME: This error is bogus and should be omitted on account of the protocol requirement itself + // being invalid. +} + From a62bf48e68956adc9b423fc03c6faac283512d36 Mon Sep 17 00:00:00 2001 From: NevinBR Date: Tue, 18 Aug 2020 18:12:35 -0400 Subject: [PATCH 234/663] [stdlib] [NFC] FloatingPointRandom.swift created (#33463) * Moved `random` methods out of FloatingPoint.swift * Added `random` methods to FloatingPointRandom.swift * Added FloatingPointRandom.swift to CMakeLists.txt * Added FloatingPointRandom.swift to GroupInfo.json * Moved filename within CMakeLists.txt --- stdlib/public/core/CMakeLists.txt | 1 + stdlib/public/core/FloatingPoint.swift | 201 ----------------- stdlib/public/core/FloatingPointRandom.swift | 215 +++++++++++++++++++ stdlib/public/core/GroupInfo.json | 3 +- 4 files changed, 218 insertions(+), 202 deletions(-) create mode 100644 stdlib/public/core/FloatingPointRandom.swift diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 56d9d5d230154..ad74e0e699039 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -211,6 +211,7 @@ set(SWIFTLIB_SOURCES CollectionOfOne.swift DiscontiguousSlice.swift Diffing.swift + FloatingPointRandom.swift Mirror.swift PlaygroundDisplay.swift CommandLine.swift diff --git a/stdlib/public/core/FloatingPoint.swift b/stdlib/public/core/FloatingPoint.swift index a6339654ff6d9..fa7ce591f6530 100644 --- a/stdlib/public/core/FloatingPoint.swift +++ b/stdlib/public/core/FloatingPoint.swift @@ -2013,205 +2013,4 @@ extension BinaryFloatingPoint where Self.RawSignificand: FixedWidthInteger { guard exact else { return nil } self = value_ } - - /// Returns a random value within the specified range, using the given - /// generator as a source for randomness. - /// - /// Use this method to generate a floating-point value within a specific - /// range when you are using a custom random number generator. This example - /// creates three new values in the range `10.0 ..< 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ..< 20.0, using: &myGenerator)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random(in:using:)` static method chooses a random value from a - /// continuous uniform distribution in `range`, and then converts that value - /// to the nearest representable value in this type. Depending on the size - /// and span of `range`, some concrete values may be represented more - /// frequently than others. - /// - /// - Note: The algorithm used to create random values may change in a future - /// version of Swift. If you're passing a generator that results in the - /// same sequence of floating-point values each time you run your program, - /// that sequence may change when your program is compiled using a - /// different version of Swift. - /// - /// - Parameters: - /// - range: The range in which to create a random value. - /// `range` must be finite and non-empty. - /// - generator: The random number generator to use when creating the - /// new random value. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random( - in range: Range, - using generator: inout T - ) -> Self { - _precondition( - !range.isEmpty, - "Can't get random value with an empty range" - ) - let delta = range.upperBound - range.lowerBound - // TODO: this still isn't quite right, because the computation of delta - // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and - // .lowerBound = -.upperBound); this should be re-written with an - // algorithm that handles that case correctly, but this precondition - // is an acceptable short-term fix. - _precondition( - delta.isFinite, - "There is no uniform distribution on an infinite range" - ) - let rand: Self.RawSignificand - if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { - rand = generator.next() - } else { - let significandCount = Self.significandBitCount + 1 - let maxSignificand: Self.RawSignificand = 1 << significandCount - // Rather than use .next(upperBound:), which has to work with arbitrary - // upper bounds, and therefore does extra work to avoid bias, we can take - // a shortcut because we know that maxSignificand is a power of two. - rand = generator.next() & (maxSignificand - 1) - } - let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) - let randFloat = delta * unitRandom + range.lowerBound - if randFloat == range.upperBound { - return Self.random(in: range, using: &generator) - } - return randFloat - } - - /// Returns a random value within the specified range. - /// - /// Use this method to generate a floating-point value within a specific - /// range. This example creates three new values in the range - /// `10.0 ..< 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ..< 20.0)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random()` static method chooses a random value from a continuous - /// uniform distribution in `range`, and then converts that value to the - /// nearest representable value in this type. Depending on the size and span - /// of `range`, some concrete values may be represented more frequently than - /// others. - /// - /// This method is equivalent to calling `random(in:using:)`, passing in the - /// system's default random generator. - /// - /// - Parameter range: The range in which to create a random value. - /// `range` must be finite and non-empty. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random(in range: Range) -> Self { - var g = SystemRandomNumberGenerator() - return Self.random(in: range, using: &g) - } - - /// Returns a random value within the specified range, using the given - /// generator as a source for randomness. - /// - /// Use this method to generate a floating-point value within a specific - /// range when you are using a custom random number generator. This example - /// creates three new values in the range `10.0 ... 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ... 20.0, using: &myGenerator)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random(in:using:)` static method chooses a random value from a - /// continuous uniform distribution in `range`, and then converts that value - /// to the nearest representable value in this type. Depending on the size - /// and span of `range`, some concrete values may be represented more - /// frequently than others. - /// - /// - Note: The algorithm used to create random values may change in a future - /// version of Swift. If you're passing a generator that results in the - /// same sequence of floating-point values each time you run your program, - /// that sequence may change when your program is compiled using a - /// different version of Swift. - /// - /// - Parameters: - /// - range: The range in which to create a random value. Must be finite. - /// - generator: The random number generator to use when creating the - /// new random value. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random( - in range: ClosedRange, - using generator: inout T - ) -> Self { - _precondition( - !range.isEmpty, - "Can't get random value with an empty range" - ) - let delta = range.upperBound - range.lowerBound - // TODO: this still isn't quite right, because the computation of delta - // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and - // .lowerBound = -.upperBound); this should be re-written with an - // algorithm that handles that case correctly, but this precondition - // is an acceptable short-term fix. - _precondition( - delta.isFinite, - "There is no uniform distribution on an infinite range" - ) - let rand: Self.RawSignificand - if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { - rand = generator.next() - let tmp: UInt8 = generator.next() & 1 - if rand == Self.RawSignificand.max && tmp == 1 { - return range.upperBound - } - } else { - let significandCount = Self.significandBitCount + 1 - let maxSignificand: Self.RawSignificand = 1 << significandCount - rand = generator.next(upperBound: maxSignificand + 1) - if rand == maxSignificand { - return range.upperBound - } - } - let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) - let randFloat = delta * unitRandom + range.lowerBound - return randFloat - } - - /// Returns a random value within the specified range. - /// - /// Use this method to generate a floating-point value within a specific - /// range. This example creates three new values in the range - /// `10.0 ... 20.0`. - /// - /// for _ in 1...3 { - /// print(Double.random(in: 10.0 ... 20.0)) - /// } - /// // Prints "18.1900709259179" - /// // Prints "14.2286325689993" - /// // Prints "13.1485686260762" - /// - /// The `random()` static method chooses a random value from a continuous - /// uniform distribution in `range`, and then converts that value to the - /// nearest representable value in this type. Depending on the size and span - /// of `range`, some concrete values may be represented more frequently than - /// others. - /// - /// This method is equivalent to calling `random(in:using:)`, passing in the - /// system's default random generator. - /// - /// - Parameter range: The range in which to create a random value. Must be finite. - /// - Returns: A random value within the bounds of `range`. - @inlinable - public static func random(in range: ClosedRange) -> Self { - var g = SystemRandomNumberGenerator() - return Self.random(in: range, using: &g) - } } diff --git a/stdlib/public/core/FloatingPointRandom.swift b/stdlib/public/core/FloatingPointRandom.swift new file mode 100644 index 0000000000000..8aeb16eb36030 --- /dev/null +++ b/stdlib/public/core/FloatingPointRandom.swift @@ -0,0 +1,215 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +extension BinaryFloatingPoint where Self.RawSignificand: FixedWidthInteger { + + /// Returns a random value within the specified range, using the given + /// generator as a source for randomness. + /// + /// Use this method to generate a floating-point value within a specific + /// range when you are using a custom random number generator. This example + /// creates three new values in the range `10.0 ..< 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ..< 20.0, using: &myGenerator)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random(in:using:)` static method chooses a random value from a + /// continuous uniform distribution in `range`, and then converts that value + /// to the nearest representable value in this type. Depending on the size + /// and span of `range`, some concrete values may be represented more + /// frequently than others. + /// + /// - Note: The algorithm used to create random values may change in a future + /// version of Swift. If you're passing a generator that results in the + /// same sequence of floating-point values each time you run your program, + /// that sequence may change when your program is compiled using a + /// different version of Swift. + /// + /// - Parameters: + /// - range: The range in which to create a random value. + /// `range` must be finite and non-empty. + /// - generator: The random number generator to use when creating the + /// new random value. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random( + in range: Range, + using generator: inout T + ) -> Self { + _precondition( + !range.isEmpty, + "Can't get random value with an empty range" + ) + let delta = range.upperBound - range.lowerBound + // TODO: this still isn't quite right, because the computation of delta + // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and + // .lowerBound = -.upperBound); this should be re-written with an + // algorithm that handles that case correctly, but this precondition + // is an acceptable short-term fix. + _precondition( + delta.isFinite, + "There is no uniform distribution on an infinite range" + ) + let rand: Self.RawSignificand + if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { + rand = generator.next() + } else { + let significandCount = Self.significandBitCount + 1 + let maxSignificand: Self.RawSignificand = 1 << significandCount + // Rather than use .next(upperBound:), which has to work with arbitrary + // upper bounds, and therefore does extra work to avoid bias, we can take + // a shortcut because we know that maxSignificand is a power of two. + rand = generator.next() & (maxSignificand - 1) + } + let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) + let randFloat = delta * unitRandom + range.lowerBound + if randFloat == range.upperBound { + return Self.random(in: range, using: &generator) + } + return randFloat + } + + /// Returns a random value within the specified range. + /// + /// Use this method to generate a floating-point value within a specific + /// range. This example creates three new values in the range + /// `10.0 ..< 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ..< 20.0)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random()` static method chooses a random value from a continuous + /// uniform distribution in `range`, and then converts that value to the + /// nearest representable value in this type. Depending on the size and span + /// of `range`, some concrete values may be represented more frequently than + /// others. + /// + /// This method is equivalent to calling `random(in:using:)`, passing in the + /// system's default random generator. + /// + /// - Parameter range: The range in which to create a random value. + /// `range` must be finite and non-empty. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random(in range: Range) -> Self { + var g = SystemRandomNumberGenerator() + return Self.random(in: range, using: &g) + } + + /// Returns a random value within the specified range, using the given + /// generator as a source for randomness. + /// + /// Use this method to generate a floating-point value within a specific + /// range when you are using a custom random number generator. This example + /// creates three new values in the range `10.0 ... 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ... 20.0, using: &myGenerator)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random(in:using:)` static method chooses a random value from a + /// continuous uniform distribution in `range`, and then converts that value + /// to the nearest representable value in this type. Depending on the size + /// and span of `range`, some concrete values may be represented more + /// frequently than others. + /// + /// - Note: The algorithm used to create random values may change in a future + /// version of Swift. If you're passing a generator that results in the + /// same sequence of floating-point values each time you run your program, + /// that sequence may change when your program is compiled using a + /// different version of Swift. + /// + /// - Parameters: + /// - range: The range in which to create a random value. Must be finite. + /// - generator: The random number generator to use when creating the + /// new random value. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random( + in range: ClosedRange, + using generator: inout T + ) -> Self { + _precondition( + !range.isEmpty, + "Can't get random value with an empty range" + ) + let delta = range.upperBound - range.lowerBound + // TODO: this still isn't quite right, because the computation of delta + // can overflow (e.g. if .upperBound = .maximumFiniteMagnitude and + // .lowerBound = -.upperBound); this should be re-written with an + // algorithm that handles that case correctly, but this precondition + // is an acceptable short-term fix. + _precondition( + delta.isFinite, + "There is no uniform distribution on an infinite range" + ) + let rand: Self.RawSignificand + if Self.RawSignificand.bitWidth == Self.significandBitCount + 1 { + rand = generator.next() + let tmp: UInt8 = generator.next() & 1 + if rand == Self.RawSignificand.max && tmp == 1 { + return range.upperBound + } + } else { + let significandCount = Self.significandBitCount + 1 + let maxSignificand: Self.RawSignificand = 1 << significandCount + rand = generator.next(upperBound: maxSignificand + 1) + if rand == maxSignificand { + return range.upperBound + } + } + let unitRandom = Self.init(rand) * (Self.ulpOfOne / 2) + let randFloat = delta * unitRandom + range.lowerBound + return randFloat + } + + /// Returns a random value within the specified range. + /// + /// Use this method to generate a floating-point value within a specific + /// range. This example creates three new values in the range + /// `10.0 ... 20.0`. + /// + /// for _ in 1...3 { + /// print(Double.random(in: 10.0 ... 20.0)) + /// } + /// // Prints "18.1900709259179" + /// // Prints "14.2286325689993" + /// // Prints "13.1485686260762" + /// + /// The `random()` static method chooses a random value from a continuous + /// uniform distribution in `range`, and then converts that value to the + /// nearest representable value in this type. Depending on the size and span + /// of `range`, some concrete values may be represented more frequently than + /// others. + /// + /// This method is equivalent to calling `random(in:using:)`, passing in the + /// system's default random generator. + /// + /// - Parameter range: The range in which to create a random value. Must be finite. + /// - Returns: A random value within the bounds of `range`. + @inlinable + public static func random(in range: ClosedRange) -> Self { + var g = SystemRandomNumberGenerator() + return Self.random(in: range, using: &g) + } +} diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index 289703802610a..8b4fbcaae345f 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -169,7 +169,8 @@ "Floating": [ "FloatingPoint.swift", "FloatingPointParsing.swift", - "FloatingPointTypes.swift"], + "FloatingPointTypes.swift", + "FloatingPointRandom.swift"], "Vector": [ "SIMDVector.swift", "SIMDVectorTypes.swift"]} From d50e3b00bf2a185635c2914a14e1a5b0bba3287b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 18 Aug 2020 18:13:23 -0400 Subject: [PATCH 235/663] Add regression test for rdar://problem/62268062 --- .../rdar62268062.swift | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 validation-test/compiler_crashers_2_fixed/rdar62268062.swift diff --git a/validation-test/compiler_crashers_2_fixed/rdar62268062.swift b/validation-test/compiler_crashers_2_fixed/rdar62268062.swift new file mode 100644 index 0000000000000..21b59a843ff98 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar62268062.swift @@ -0,0 +1,41 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public protocol HorseSaddle {} +public enum EnglishSaddle : HorseSaddle {} + +public enum WesternSaddle : HorseSaddle {} + +public protocol Horse { + associatedtype Body : Horse + + associatedtype Saddle: HorseSaddle + + var body: Body { get } +} + +extension Horse { + typealias Saddle = Body.Saddle +} + +public struct DraftHorse : Pony { + public typealias Saddle = EnglishSaddle + public typealias Body = Never + var contents: T +} + +// MARK: - Implementation detail + +extension Never : Horse { + public typealias Saddle = EnglishSaddle + public typealias Body = Never + + public var body: Never { + switch self {} + } +} + +protocol Pony : Horse where Body == Never {} +extension Pony { + public var body: Never { fatalError() } +} + From 3d6c6b4a59f239f670d2ddbe2771a66a3a07f62f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 18 Aug 2020 17:37:04 -0700 Subject: [PATCH 236/663] Revert "Sema: Don't need to derive CaseIterable's AllCases associated type" This reverts commit 3ae31d5173053e76764ac386150cd4dd2276219c. --- lib/Sema/DerivedConformanceCaseIterable.cpp | 24 +++++++++++++++++++++ lib/Sema/DerivedConformances.h | 6 ++++++ lib/Sema/TypeCheckProtocol.cpp | 2 ++ stdlib/public/core/CompilerProtocols.swift | 2 +- test/IDE/complete_override.swift | 3 ++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/Sema/DerivedConformanceCaseIterable.cpp b/lib/Sema/DerivedConformanceCaseIterable.cpp index 14d3309936918..bc809b4e53930 100644 --- a/lib/Sema/DerivedConformanceCaseIterable.cpp +++ b/lib/Sema/DerivedConformanceCaseIterable.cpp @@ -69,6 +69,15 @@ static ArraySliceType *computeAllCasesType(NominalTypeDecl *enumDecl) { return ArraySliceType::get(enumType); } +static Type deriveCaseIterable_AllCases(DerivedConformance &derived) { + // enum SomeEnum : CaseIterable { + // @derived + // typealias AllCases = [SomeEnum] + // } + auto *rawInterfaceType = computeAllCasesType(cast(derived.Nominal)); + return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType); +} + ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { // Conformance can't be synthesized in an extension. if (checkAndDiagnoseDisallowedContext(requirement)) @@ -102,3 +111,18 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { return propDecl; } + +Type DerivedConformance::deriveCaseIterable(AssociatedTypeDecl *assocType) { + // Check that we can actually derive CaseIterable for this type. + if (!canDeriveConformance(Nominal)) + return nullptr; + + if (assocType->getName() == Context.Id_AllCases) { + return deriveCaseIterable_AllCases(*this); + } + + Context.Diags.diagnose(assocType->getLoc(), + diag::broken_case_iterable_requirement); + return nullptr; +} + diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index 3465402b7a9d6..c5dba4bb20172 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -163,6 +163,12 @@ class DerivedConformance { /// \returns the derived member, which will also be added to the type. ValueDecl *deriveCaseIterable(ValueDecl *requirement); + /// Derive a CaseIterable type witness for an enum if it has no associated + /// values for any of its cases. + /// + /// \returns the derived member, which will also be added to the type. + Type deriveCaseIterable(AssociatedTypeDecl *assocType); + /// Determine if a RawRepresentable requirement can be derived for a type. /// /// This is implemented for non-empty enums without associated values, diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 83f8444d64122..e067f7ce69ccc 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5763,6 +5763,8 @@ TypeChecker::deriveTypeWitness(DeclContext *DC, switch (*knownKind) { case KnownProtocolKind::RawRepresentable: return std::make_pair(derived.deriveRawRepresentable(AssocType), nullptr); + case KnownProtocolKind::CaseIterable: + return std::make_pair(derived.deriveCaseIterable(AssocType), nullptr); case KnownProtocolKind::Differentiable: return derived.deriveDifferentiable(AssocType); default: diff --git a/stdlib/public/core/CompilerProtocols.swift b/stdlib/public/core/CompilerProtocols.swift index 784fee1d14507..ca92b3d2b94cb 100644 --- a/stdlib/public/core/CompilerProtocols.swift +++ b/stdlib/public/core/CompilerProtocols.swift @@ -249,7 +249,7 @@ extension RawRepresentable where RawValue: Hashable, Self: Hashable { /// demonstrates this automatic implementation. public protocol CaseIterable { /// A type that can represent a collection of all values of this type. - associatedtype AllCases: Collection = [Self] + associatedtype AllCases: Collection where AllCases.Element == Self /// A collection of all values of this type. diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 7f186a8aafaa6..4213dfa1df6ee 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -896,10 +896,11 @@ struct SynthesizedConformance3: Hashable { enum SynthesizedConformance4: CaseIterable { case a, b, c, d #^OVERRIDE_SYNTHESIZED_4^# -// OVERRIDE_SYNTHESIZED_4: Begin completions, 3 items +// OVERRIDE_SYNTHESIZED_4: Begin completions, 4 items // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceVar]/Super/IsSystem: var hashValue: Int // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceMethod]/Super/IsSystem: func hash(into hasher: inout Hasher) {|}; // OVERRIDE_SYNTHESIZED_4-DAG: Decl[StaticVar]/Super/IsSystem: static var allCases: [SynthesizedConformance4]; +// OVERRIDE_SYNTHESIZED_4-DAG: Decl[AssociatedType]/Super/IsSystem: typealias AllCases = {#(Type)#}; } class SynthesizedConformance5: SynthesizedConformance2 { From ac5016bc945feed7d62a7108bcff2ada7ca670be Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 27 Jul 2020 14:03:30 -0700 Subject: [PATCH 237/663] [opt-remark] Skip implicit top level functions and autogenerated compiler functions. This eliminates opt-remarks on initializers/friends, e.x.: ``` struct KlassPair { var lhs: Klass // expected-remark {{retain of type 'Klass'}} // expected-note @-1 {{of 'self.lhs'}} // expected-remark @-2 {{release of type 'Klass'}} // expected-note @-3 {{of 'self.lhs'}} var rhs: Klass // expected-remark {{retain of type 'Klass'}} // expected-note @-1 {{of 'self.rhs'}} // expected-remark @-2 {{release of type 'Klass'}} // expected-note @-3 {{of 'self.rhs'}} } ``` becomes: ``` struct KlassPair { var lhs: Klass var rhs: Klass } ``` I also added an -Xllvm option (-optremarkgen-visit-implicit-autogen-funcs) that will force these to be emitted as a compiler knob for compiler developers. There is a test that validates the behavior. --- .../Transforms/OptRemarkGenerator.cpp | 22 +++++++++++++++++++ ...enerator-force-emit-implicit-autogen.swift | 15 +++++++++++++ test/SILOptimizer/opt-remark-generator.swift | 18 +++------------ 3 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index b20890a6b1cfd..c6cb5c7e6a5e5 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -30,10 +30,17 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" using namespace swift; +static llvm::cl::opt ForceVisitImplicitAutogeneratedFunctions( + "optremarkgen-visit-implicit-autogen-funcs", llvm::cl::Hidden, + llvm::cl::desc( + "Emit opt remarks even on implicit and autogenerated functions"), + llvm::cl::init(false)); + //===----------------------------------------------------------------------===// // Utility //===----------------------------------------------------------------------===// @@ -347,6 +354,21 @@ class OptRemarkGenerator : public SILFunctionTransform { return; auto *fn = getFunction(); + + // Skip top level implicit functions and top level autogenerated functions, + // unless we were asked by the user to emit them. + if (!ForceVisitImplicitAutogeneratedFunctions) { + // Skip implicit functions generated by Sema. + if (auto *ctx = fn->getDeclContext()) + if (auto *decl = ctx->getAsDecl()) + if (decl->isImplicit()) + return; + // Skip autogenerated functions generated by SILGen. + if (auto loc = fn->getDebugScope()->getLoc()) + if (loc.isAutoGenerated()) + return; + } + LLVM_DEBUG(llvm::dbgs() << "Visiting: " << fn->getName() << "\n"); auto &rcfi = *getAnalysis()->get(fn); OptRemarkGeneratorInstructionVisitor visitor(*fn, rcfi); diff --git a/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift b/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift new file mode 100644 index 0000000000000..550a53e0dc120 --- /dev/null +++ b/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift @@ -0,0 +1,15 @@ +// RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify -Xllvm -optremarkgen-visit-implicit-autogen-funcs=1 + +class Klass {} + +struct KlassPair { + var lhs: Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-1 {{of 'self.lhs'}} + // expected-remark @-2 {{release of type 'Klass'}} + // expected-note @-3 {{of 'self.lhs'}} + var rhs: Klass // expected-remark {{retain of type 'Klass'}} + // expected-note @-1 {{of 'self.rhs'}} + // expected-remark @-2 {{release of type 'Klass'}} + // expected-note @-3 {{of 'self.rhs'}} +} + diff --git a/test/SILOptimizer/opt-remark-generator.swift b/test/SILOptimizer/opt-remark-generator.swift index 1991d1a083f8c..c354552f173af 100644 --- a/test/SILOptimizer/opt-remark-generator.swift +++ b/test/SILOptimizer/opt-remark-generator.swift @@ -31,13 +31,7 @@ case third } struct StructWithOwner { - // This retain is from the initializers of owner. - // - // TODO: Should we emit this? - var owner = Klass() // expected-remark {{retain of type 'Klass'}} - // expected-note @-1 {{of 'self.owner'}} - // expected-remark @-2 {{release of type 'Klass'}} - // expected-note @-3 {{of 'self.owner'}} + var owner = Klass() var state = TrivialState.first } @@ -66,14 +60,8 @@ func callingAnInitializerStructWithOwner(x: Klass) -> StructWithOwner { } struct KlassPair { - var lhs: Klass // expected-remark {{retain of type 'Klass'}} - // expected-note @-1 {{of 'self.lhs'}} - // expected-remark @-2 {{release of type 'Klass'}} - // expected-note @-3 {{of 'self.lhs'}} - var rhs: Klass // expected-remark {{retain of type 'Klass'}} - // expected-note @-1 {{of 'self.rhs'}} - // expected-remark @-2 {{release of type 'Klass'}} - // expected-note @-3 {{of 'self.rhs'}} + var lhs: Klass + var rhs: Klass } func printKlassPair(x : KlassPair) { From 9ecd2a00226078d5392b20bc8f69b27c90e4c920 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 18 Aug 2020 17:56:11 -0700 Subject: [PATCH 238/663] build: switch to `cl` instead of `clang-cl` for lldb clang has a bug where the template handling triggers an assertion. This switches the compiler to MSVC's compiler as a temporary workaround. --- utils/build-windows-rebranch.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/build-windows-rebranch.bat b/utils/build-windows-rebranch.bat index 30c82272f6a66..feb14fe07d361 100644 --- a/utils/build-windows-rebranch.bat +++ b/utils/build-windows-rebranch.bat @@ -279,8 +279,8 @@ cmake^ -B "%build_root%\lldb"^ -G Ninja^ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ - -DCMAKE_C_COMPILER=clang-cl^ - -DCMAKE_CXX_COMPILER=clang-cl^ + -DCMAKE_C_COMPILER=cl^ + -DCMAKE_CXX_COMPILER=cl^ -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ From c8c807f349f34bfbebeca7fc5adaf80b57c51570 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 18 Aug 2020 14:25:04 -0700 Subject: [PATCH 239/663] Consistently use toggle_true instead of store_true when selected projects. This allows for child cascading presets to mixin a parent preset and then selectively turn off these projects. store_true in contrast can not be overwritten making cascading impossible. --- .../build_swift/driver_arguments.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 62acc4557d027..838aa5afa84ff 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -549,16 +549,16 @@ def create_argument_parser(): # ------------------------------------------------------------------------- in_group('Options to select projects') - option('--infer', store_true('infer_dependencies'), + option('--infer', toggle_true('infer_dependencies'), help='Infer any downstream dependencies from enabled projects') - option(['-l', '--lldb'], store_true('build_lldb'), + option(['-l', '--lldb'], toggle_true('build_lldb'), help='build LLDB') - option(['-b', '--llbuild'], store_true('build_llbuild'), + option(['-b', '--llbuild'], toggle_true('build_llbuild'), help='build llbuild') - option(['--libcxx'], store_true('build_libcxx'), + option(['--libcxx'], toggle_true('build_libcxx'), help='build libcxx') option(['-p', '--swiftpm'], toggle_true('build_swiftpm'), @@ -567,16 +567,16 @@ def create_argument_parser(): option(['--install-swiftpm'], toggle_true('install_swiftpm'), help='install swiftpm') - option(['--swiftsyntax'], store_true('build_swiftsyntax'), + option(['--swiftsyntax'], toggle_true('build_swiftsyntax'), help='build swiftSyntax') - option(['--skstresstester'], store_true('build_skstresstester'), + option(['--skstresstester'], toggle_true('build_skstresstester'), help='build the SourceKit stress tester') - option(['--swiftformat'], store_true('build_swiftformat'), + option(['--swiftformat'], toggle_true('build_swiftformat'), help='build swift-format') - option(['--swiftevolve'], store_true('build_swiftevolve'), + option(['--swiftevolve'], toggle_true('build_swiftevolve'), help='build the swift-evolve tool') option(['--swift-driver'], toggle_true('build_swift_driver'), @@ -630,13 +630,13 @@ def create_argument_parser(): option('--playgroundsupport', toggle_true('build_playgroundsupport'), help='build PlaygroundSupport') option('--install-playgroundsupport', - store_true('install_playgroundsupport'), + toggle_true('install_playgroundsupport'), help='install playground support') option('--build-ninja', toggle_true, help='build the Ninja tool') - option(['--build-libparser-only'], store_true('build_libparser_only'), + option(['--build-libparser-only'], toggle_true('build_libparser_only'), help='build only libParser for SwiftSyntax') option('--skip-build-clang-tools-extra', From e42037a8c2835f3d25ac272f51bf45d5cde4fa60 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 18 Aug 2020 17:38:01 -0700 Subject: [PATCH 240/663] Restore AllCases Default While we cannot yet remove the synthesis of AllCases without some extra coordination with the SDKs, we can at least leave the default behind since it is always going to be correct, if a little duplicative. --- stdlib/public/core/CompilerProtocols.swift | 2 +- test/IDE/complete_override.swift | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/stdlib/public/core/CompilerProtocols.swift b/stdlib/public/core/CompilerProtocols.swift index ca92b3d2b94cb..784fee1d14507 100644 --- a/stdlib/public/core/CompilerProtocols.swift +++ b/stdlib/public/core/CompilerProtocols.swift @@ -249,7 +249,7 @@ extension RawRepresentable where RawValue: Hashable, Self: Hashable { /// demonstrates this automatic implementation. public protocol CaseIterable { /// A type that can represent a collection of all values of this type. - associatedtype AllCases: Collection + associatedtype AllCases: Collection = [Self] where AllCases.Element == Self /// A collection of all values of this type. diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 4213dfa1df6ee..7f186a8aafaa6 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -896,11 +896,10 @@ struct SynthesizedConformance3: Hashable { enum SynthesizedConformance4: CaseIterable { case a, b, c, d #^OVERRIDE_SYNTHESIZED_4^# -// OVERRIDE_SYNTHESIZED_4: Begin completions, 4 items +// OVERRIDE_SYNTHESIZED_4: Begin completions, 3 items // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceVar]/Super/IsSystem: var hashValue: Int // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceMethod]/Super/IsSystem: func hash(into hasher: inout Hasher) {|}; // OVERRIDE_SYNTHESIZED_4-DAG: Decl[StaticVar]/Super/IsSystem: static var allCases: [SynthesizedConformance4]; -// OVERRIDE_SYNTHESIZED_4-DAG: Decl[AssociatedType]/Super/IsSystem: typealias AllCases = {#(Type)#}; } class SynthesizedConformance5: SynthesizedConformance2 { From 57f2944aad1d08d9bbd530a8534e52895c783eb1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 18 Aug 2020 17:04:20 -0700 Subject: [PATCH 241/663] Add A Reproducer For rdar://48443680 The ModuleManager in Clang maintains a mapping from FileEntry nodes to ModuleFile data. Because FileEntry nodes are unique'd by underlying inode number, an attacker can craft a collision by ensuring that two different PCMs share an inode number. This failure can be encountered with some regularity in a highly concurrent compilation session on filesystems that use Orlov's Algorithm to allocate inode numbers (like ext4 on Linux). Here, we use a much simpler algorithm that forgets that PCMs have distinct inode numbers. A future version of clang will increase the entropy of the key value to take into account the mod time and size, which we also conveniently map to 0 to throw it off our trail. --- .../ClangImporter/ClangImporterTests.cpp | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/unittests/ClangImporter/ClangImporterTests.cpp b/unittests/ClangImporter/ClangImporterTests.cpp index e353fba57745f..4068678fd8433 100644 --- a/unittests/ClangImporter/ClangImporterTests.cpp +++ b/unittests/ClangImporter/ClangImporterTests.cpp @@ -6,6 +6,10 @@ #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangImporterOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/FileSystemStatCache.h" +#include "clang/Frontend/CompilerInstance.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -54,7 +58,6 @@ TEST(ClangImporterTest, emitPCHInMemory) { // Create the includes. std::string include = createFilename(temp, "include"); ASSERT_FALSE(llvm::sys::fs::create_directory(include)); - options.ExtraArgs.emplace_back("-nosysteminc"); options.ExtraArgs.emplace_back((llvm::Twine("-I") + include).str()); ASSERT_FALSE(emitFileWithContents(include, "module.modulemap", "module A {\n" @@ -88,3 +91,105 @@ TEST(ClangImporterTest, emitPCHInMemory) { ASSERT_FALSE(emitFileWithContents(PCH, "garbage")); ASSERT_TRUE(importer->canReadPCH(PCH)); } + +class ForgetfulStatCache : public clang::FileSystemStatCache { +private: + std::unique_ptr RealStatCache; + +public: + ForgetfulStatCache() { + RealStatCache = std::make_unique(); + } + ~ForgetfulStatCache() = default; + + std::error_code getStat(StringRef Path, llvm::vfs::Status &Status, + bool isFile, + std::unique_ptr *F, + llvm::vfs::FileSystem &FS) override { + if (llvm::sys::path::extension(Path) == ".pcm") { + const auto UID = llvm::sys::fs::UniqueID(1, std::numeric_limits::max()); + Status = llvm::vfs::Status(Path, UID, + /*MTime*/{}, /*User*/0, /*Group*/0, + /*Size*/0, + llvm::sys::fs::file_type::regular_file, + llvm::sys::fs::perms::all_all); + return std::error_code(); + } + + return clang::FileSystemStatCache::get(Path, Status, isFile, F, + RealStatCache.get(), FS); + } +}; + +TEST(ClangImporterTest, missingSubmodule) { + // Create a temporary cache on disk and clean it up at the end. + ClangImporterOptions options; + SmallString<256> temp; + ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory( + "ClangImporterTest.missingSubmodule", temp)); + SWIFT_DEFER { llvm::sys::fs::remove_directories(temp); }; + + // Create a cache subdirectory for the modules and PCH. + std::string cache = createFilename(temp, "cache"); + ASSERT_FALSE(llvm::sys::fs::create_directory(cache)); + options.ModuleCachePath = cache; + options.PrecompiledHeaderOutputDir = cache; + + // Create the includes. + std::string include1 = createFilename(temp, "include1"); + ASSERT_FALSE(llvm::sys::fs::create_directory(include1)); + + std::string include2 = createFilename(temp, "include2"); + ASSERT_FALSE(llvm::sys::fs::create_directory(include2)); + + options.ExtraArgs.emplace_back((llvm::Twine("-I") + include1).str()); + options.ExtraArgs.emplace_back((llvm::Twine("-I") + include2).str()); + options.ExtraArgs.emplace_back("-DEXTRA_C_DEFINE=2"); + + ASSERT_FALSE(emitFileWithContents(include1, "module.modulemap", + "module CLib1 {\n" + " umbrella header \"" + include1 + "/Clib1.h\"\n" + " export * \n" + "}\n" + "module CLib2 {\n" + " umbrella header \"" + include2 + "/Clib2.h\"\n" + " export * \n" + "}\n")); + ASSERT_FALSE(emitFileWithContents(include1, "CLib1.h", + "#if !defined(EXTRA_C_DEFINE) || EXTRA_C_DEFINE != 2\n" + "#error \"unexpected compiler flags\"\n" + "#endif\n" + "void foo(void);\n")); + ASSERT_FALSE(emitFileWithContents(include2, "CLib2.h", + "#if !defined(EXTRA_C_DEFINE) || EXTRA_C_DEFINE != 2\n" + "#error \"unexpected compiler flags\"\n" + "#endif\n" + "void foo(void);\n")); + + // Set up the importer. + swift::LangOptions langOpts; + langOpts.Target = llvm::Triple("x86_64", "apple", "darwin"); + swift::TypeCheckerOptions typeckOpts; + INITIALIZE_LLVM(); + swift::SearchPathOptions searchPathOpts; + swift::SourceManager sourceMgr; + swift::DiagnosticEngine diags(sourceMgr); + std::unique_ptr context( + ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags)); + auto importer = ClangImporter::create(*context, options); + + // Install a stats cache that conveniently "forgets" that PCMs have different + // underlying FileEntry values. + importer->getClangInstance() + .getFileManager() + .setStatCache(std::make_unique()); + + context->addModuleLoader(std::move(importer)); + + auto CLib1 = context->getIdentifier("CLib1"); + auto CLib2 = context->getIdentifier("CLib2"); + // The first load succeeds and primes the ModuleManager with PCM data. + (void)context->getModule({ Located{ CLib1, {} } }); + // The second load fails because we collide in the ModuleManager. + ASSERT_TRUE(context->getModule({ Located{ CLib2, {} } }) == nullptr); +} From 876fe2f639f2992f5fcee955bf77ceb2805b91b3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 18 Aug 2020 23:43:54 -0400 Subject: [PATCH 242/663] Sema: Redeclaration checking should not mark implicit decls as invalid If both the 'other' and 'current' declarations are implicit, we don't emit a diagnostic unless they are both derived from property wrappers or lazy property storage. However, we would still call setInvalid() unconditionally, which splats an ErrorType into the interface type, which would crash in the AST verifier if no other diagnostic was emitted. Fixes . --- lib/Sema/TypeCheckDeclPrimary.cpp | 56 ++++++++++--------- .../rdar67259506.swift | 29 ++++++++++ 2 files changed, 59 insertions(+), 26 deletions(-) create mode 100644 validation-test/compiler_crashers_2_fixed/rdar67259506.swift diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index d00d1dcc8f95c..95f137573b909 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -754,35 +754,38 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const { declToDiagnose->diagnose(diag::invalid_redecl_implicit, current->getDescriptiveKind(), isProtocolRequirement, other->getName()); - } - // Emit a specialized note if the one of the declarations is - // the backing storage property ('_foo') or projected value - // property ('$foo') for a wrapped property. The backing or - // projected var has the same source location as the wrapped - // property we diagnosed above, so we don't need to extract - // the original property. - const VarDecl *varToDiagnose = nullptr; - auto kind = PropertyWrapperSynthesizedPropertyKind::Backing; - if (auto currentVD = dyn_cast(current)) { - if (auto currentKind = - currentVD->getPropertyWrapperSynthesizedPropertyKind()) { - varToDiagnose = currentVD; - kind = *currentKind; + // Emit a specialized note if the one of the declarations is + // the backing storage property ('_foo') or projected value + // property ('$foo') for a wrapped property. The backing or + // projected var has the same source location as the wrapped + // property we diagnosed above, so we don't need to extract + // the original property. + const VarDecl *varToDiagnose = nullptr; + auto kind = PropertyWrapperSynthesizedPropertyKind::Backing; + if (auto currentVD = dyn_cast(current)) { + if (auto currentKind = + currentVD->getPropertyWrapperSynthesizedPropertyKind()) { + varToDiagnose = currentVD; + kind = *currentKind; + } } - } - if (auto otherVD = dyn_cast(other)) { - if (auto otherKind = - otherVD->getPropertyWrapperSynthesizedPropertyKind()) { - varToDiagnose = otherVD; - kind = *otherKind; + if (auto otherVD = dyn_cast(other)) { + if (auto otherKind = + otherVD->getPropertyWrapperSynthesizedPropertyKind()) { + varToDiagnose = otherVD; + kind = *otherKind; + } + } + + if (varToDiagnose) { + assert(declToDiagnose); + varToDiagnose->diagnose( + diag::invalid_redecl_implicit_wrapper, varToDiagnose->getName(), + kind == PropertyWrapperSynthesizedPropertyKind::Backing); } - } - if (varToDiagnose) { - varToDiagnose->diagnose( - diag::invalid_redecl_implicit_wrapper, varToDiagnose->getName(), - kind == PropertyWrapperSynthesizedPropertyKind::Backing); + current->setInvalid(); } } else { ctx.Diags.diagnoseWithNotes( @@ -790,8 +793,9 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const { current->getName()), [&]() { other->diagnose(diag::invalid_redecl_prev, other->getName()); }); + + current->setInvalid(); } - current->setInvalid(); } // Make sure we don't do this checking again for the same decl. We also diff --git a/validation-test/compiler_crashers_2_fixed/rdar67259506.swift b/validation-test/compiler_crashers_2_fixed/rdar67259506.swift new file mode 100644 index 0000000000000..4f3360980adc4 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar67259506.swift @@ -0,0 +1,29 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public func foo(_: T, _: S.A) {} + +public protocol P { + associatedtype A + + func foo() -> A +} + +public protocol Q { + associatedtype A + + func bar() -> A +} + +public struct S {} + +extension S : P where T : P { + public func foo() -> Int { + return 0 + } +} + +extension S : Q where T : Q { + public func bar() -> Int { + return 0 + } +} From b183c69d4dfeb8cd59d154551a8d62f1b5eb531b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 18 Aug 2020 23:53:49 -0400 Subject: [PATCH 243/663] Add regression test for https://bugs.swift.org/browse/SR-13141 --- .../compiler_crashers_2_fixed/sr13141.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 validation-test/compiler_crashers_2_fixed/sr13141.swift diff --git a/validation-test/compiler_crashers_2_fixed/sr13141.swift b/validation-test/compiler_crashers_2_fixed/sr13141.swift new file mode 100644 index 0000000000000..fe403d1ce6c1c --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr13141.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-frontend -emit-ir %s + +public protocol Book { + associatedtype Name +} +public protocol BookDecorator: Book where Name == DecoratedBook.Name { + associatedtype DecoratedBook: Book + associatedtype Name = DecoratedBook.Name +} +public class ConcreteBookDecorator: BookDecorator { + public typealias DecoratedBook = T +} From 487f6d9c47d40520a08019b74a890d7ce329097c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 18 Aug 2020 23:56:50 -0400 Subject: [PATCH 244/663] Add regression test for https://bugs.swift.org/browse/SR-12691 --- .../compiler_crashers_2_fixed/sr12691.swift | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 validation-test/compiler_crashers_2_fixed/sr12691.swift diff --git a/validation-test/compiler_crashers_2_fixed/sr12691.swift b/validation-test/compiler_crashers_2_fixed/sr12691.swift new file mode 100644 index 0000000000000..33c98979944fd --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr12691.swift @@ -0,0 +1,23 @@ +// RUN: not %target-swift-frontend -typecheck %s + +struct CountSteps1 : Collection { + init(count: Int) { self.count = count } + var count: Int + + var startIndex: Int { 0 } + var endIndex: Int { count } + func index(after i: Int) -> Int { + totalSteps += 1 + return i + 1 + } + subscript(i: Int) -> Int { return i } +} + +extension CountSteps1 + : RandomAccessCollection, BidirectionalCollection + where T : Equatable +{ + func index(_ i: Index, offsetBy d: Int) -> Index { + return i + d + } +} From 471f1ee3afa874fb234fff971f1052a193de8163 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 18 Aug 2020 20:58:39 -0700 Subject: [PATCH 245/663] [Constraint solver] Disable pattern type "optimization" involving weak types. Fix a regression introduced by moving the type checking of closure captures into the constraint system. The pattern-type optimization for initializations was causing inference of a double-optional where there shouldn't be one, manifesting in a failure involving implicitly unwrapped optionals and `weak self` captures. Fixes rdar://problem/67351438. --- lib/Sema/CSGen.cpp | 29 ++++++++++------------------- test/expr/closure/single_expr.swift | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0891e23c6474c..985d557a112fe 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2189,6 +2189,12 @@ namespace { Type varType; + // Determine whether optionality will be required. + auto ROK = ReferenceOwnership::Strong; + if (auto *OA = var->getAttrs().getAttribute()) + ROK = OA->get(); + auto optionality = optionalityOf(ROK); + // If we have a type from an initializer expression, and that // expression does not produce an InOut type, use it. This // will avoid exponential typecheck behavior in the case of @@ -2197,18 +2203,17 @@ namespace { // FIXME: This should be handled in the solver, not here. // // Otherwise, create a new type variable. - bool assumedInitializerType = false; if (!var->hasNonPatternBindingInit() && - !var->hasAttachedPropertyWrapper()) { + !var->hasAttachedPropertyWrapper() && + optionality != ReferenceOwnershipOptionality::Required) { if (auto boundExpr = locator.trySimplifyToExpr()) { if (!boundExpr->isSemanticallyInOutExpr()) { varType = CS.getType(boundExpr)->getRValueType(); - assumedInitializerType = true; } } } - if (!assumedInitializerType) + if (!varType) varType = CS.createTypeVariable(CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); @@ -2226,22 +2231,8 @@ namespace { // If there is an externally-imposed type. - auto ROK = ReferenceOwnership::Strong; - if (auto *OA = var->getAttrs().getAttribute()) - ROK = OA->get(); - switch (optionalityOf(ROK)) { + switch (optionality) { case ReferenceOwnershipOptionality::Required: - if (assumedInitializerType) { - // Already Optional - if (varType->getOptionalObjectType()) - break; - - // Create a fresh type variable to handle overloaded expressions. - if (varType->is()) - varType = CS.createTypeVariable(CS.getConstraintLocator(locator), - TVO_CanBindToNoEscape); - } - varType = TypeChecker::getOptionalType(var->getLoc(), varType); assert(!varType->hasError()); diff --git a/test/expr/closure/single_expr.swift b/test/expr/closure/single_expr.swift index ac3d7a7a94aad..62960ff837b6f 100644 --- a/test/expr/closure/single_expr.swift +++ b/test/expr/closure/single_expr.swift @@ -104,3 +104,20 @@ missionCritical(storage: { haltAndCatchFire() }) enum E { } func takesAnotherUninhabitedType(e: () -> E) {} takesAnotherUninhabitedType { haltAndCatchFire() } + +// Weak capture bug caught by rdar://problem/67351438 +class Y { + var toggle: Bool = false + + func doSomething(animated: Bool, completionHandler: (Int, Int) -> Void) { } +} + +class X { + private(set) var someY: Y! + + func doSomething() { + someY?.doSomething(animated: true, completionHandler: { [weak someY] _, _ in + someY?.toggle = true + }) + } +} From b3509fcab3c0f55d918fe2a7fa88012e769b19af Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 19 Aug 2020 08:35:21 -0700 Subject: [PATCH 246/663] Fix build with SWIFT_RUNTIME_MACHO_NO_DYLD=1 in ImageInspectionStatic.cpp --- .../public/runtime/ImageInspectionStatic.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/stdlib/public/runtime/ImageInspectionStatic.cpp b/stdlib/public/runtime/ImageInspectionStatic.cpp index 8c0d42253c61f..8b95ca01d38b4 100644 --- a/stdlib/public/runtime/ImageInspectionStatic.cpp +++ b/stdlib/public/runtime/ImageInspectionStatic.cpp @@ -33,7 +33,8 @@ using namespace swift; void swift::initializeProtocolLookup() { void *start; uintptr_t size; - GET_SECTION_START_AND_SIZE(start, size, TextSegment, ProtocolsSection); + GET_SECTION_START_AND_SIZE(start, size, MachOTextSegment, + MachOProtocolsSection); if (start == nullptr || size == 0) return; addImageProtocolsBlockCallbackUnsafe(start, size); @@ -42,8 +43,8 @@ void swift::initializeProtocolLookup() { void swift::initializeProtocolConformanceLookup() { void *start; uintptr_t size; - GET_SECTION_START_AND_SIZE(start, size, TextSegment, - ProtocolConformancesSection); + GET_SECTION_START_AND_SIZE(start, size, MachOTextSegment, + MachOProtocolConformancesSection); if (start == nullptr || size == 0) return; addImageProtocolConformanceBlockCallbackUnsafe(start, size); @@ -51,8 +52,8 @@ void swift::initializeProtocolConformanceLookup() { void swift::initializeTypeMetadataRecordLookup() { void *start; uintptr_t size; - GET_SECTION_START_AND_SIZE(start, size, TextSegment, - TypeMetadataRecordSection); + GET_SECTION_START_AND_SIZE(start, size, MachOTextSegment, + MachOTypeMetadataRecordSection); if (start == nullptr || size == 0) return; addImageTypeMetadataRecordBlockCallbackUnsafe(start, size); @@ -61,14 +62,14 @@ void swift::initializeTypeMetadataRecordLookup() { void swift::initializeDynamicReplacementLookup() { void *start1; uintptr_t size1; - GET_SECTION_START_AND_SIZE(start1, size1, TextSegment, - DynamicReplacementSection); + GET_SECTION_START_AND_SIZE(start1, size1, MachOTextSegment, + MachODynamicReplacementSection); if (start1 == nullptr || size1 == 0) return; void *start2; uintptr_t size2; - GET_SECTION_START_AND_SIZE(start2, size2, TextSegment, - DynamicReplacementSection); + GET_SECTION_START_AND_SIZE(start2, size2, MachOTextSegment, + MachODynamicReplacementSection); if (start2 == nullptr || size2 == 0) return; addImageDynamicReplacementBlockCallback(start1, size1, start2, size2); From 4145ef7a12e0330c93adf104cbebe7cba951b0ec Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 18 Aug 2020 12:20:53 -0700 Subject: [PATCH 247/663] Revert "[SIL] Add flag to SILFunction to indicate async." This reverts commit 6b28c2fe89614386b6835c9f1340a9df6152b1f5. --- include/swift/SIL/SILFunction.h | 7 ------- lib/SIL/IR/SILFunction.cpp | 2 +- lib/SIL/IR/SILFunctionBuilder.cpp | 4 ---- lib/SIL/IR/SILPrinter.cpp | 3 --- lib/SIL/Parser/ParseSIL.cpp | 24 +++++++++++------------- lib/Serialization/DeserializeSIL.cpp | 14 ++++---------- lib/Serialization/SILFormat.h | 1 - lib/Serialization/SerializeSIL.cpp | 2 +- test/SILGen/async.swift | 20 -------------------- 9 files changed, 17 insertions(+), 60 deletions(-) delete mode 100644 test/SILGen/async.swift diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 8125736fc391f..ae3f940d21ad4 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -274,9 +274,6 @@ class SILFunction /// that it may have unboxed capture (i.e. @inout_aliasable parameters). unsigned IsWithoutActuallyEscapingThunk : 1; - /// True if this function is an async function. - unsigned IsAsync : 1; - /// If != OptimizationMode::NotSet, the optimization mode specified with an /// function attribute. unsigned OptMode : NumOptimizationModeBits; @@ -504,10 +501,6 @@ class SILFunction IsWithoutActuallyEscapingThunk = val; } - bool isAsync() const { return IsAsync; } - - void setAsync(bool val = true) { IsAsync = val; } - /// Returns the calling convention used by this entry point. SILFunctionTypeRepresentation getRepresentation() const { return getLoweredFunctionType()->getRepresentation(); diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index 8f4d425549d02..dd118be43c2ae 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -107,7 +107,7 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name, ExactSelfClass(isExactSelfClass), Inlined(false), Zombie(false), HasOwnership(true), WasDeserializedCanonical(false), IsWithoutActuallyEscapingThunk(false), - IsAsync(false), OptMode(unsigned(OptimizationMode::NotSet)), + OptMode(unsigned(OptimizationMode::NotSet)), EffectsKindAttr(unsigned(E)) { assert(!Transparent || !IsDynamicReplaceable); validateSubclassScope(classSubclassScope, isThunk, nullptr); diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index c28ba05090b1b..b56d34ea74d00 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -217,10 +217,6 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( } addFunctionAttributes(F, decl->getAttrs(), mod, getOrCreateDeclaration, constant); - - if (auto *funcDecl = dyn_cast(decl)) { - F->setAsync(funcDecl->hasAsync()); - } } return F; diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index eed8fab9abf36..fe0f2dea86795 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2598,9 +2598,6 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { if (isWithoutActuallyEscapingThunk()) OS << "[without_actually_escaping] "; - if (isAsync()) - OS << "[async] "; - switch (getSpecialPurpose()) { case SILFunction::Purpose::None: break; diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 00ceaf52ca02e..f70112cbcdaad 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -919,7 +919,6 @@ static bool parseDeclSILOptional(bool *isTransparent, bool *isWeakImported, AvailabilityContext *availability, bool *isWithoutActuallyEscapingThunk, - bool *isAsync, SmallVectorImpl *Semantics, SmallVectorImpl *SpecAttrs, ValueDecl **ClangDecl, @@ -958,8 +957,6 @@ static bool parseDeclSILOptional(bool *isTransparent, else if (isWithoutActuallyEscapingThunk && SP.P.Tok.getText() == "without_actually_escaping") *isWithoutActuallyEscapingThunk = true; - else if (isAsync && SP.P.Tok.getText() == "async") - *isAsync = true; else if (specialPurpose && SP.P.Tok.getText() == "global_init") *specialPurpose = SILFunction::Purpose::GlobalInit; else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter") @@ -5682,7 +5679,6 @@ bool SILParserState::parseDeclSIL(Parser &P) { bool isWeakImported = false; AvailabilityContext availability = AvailabilityContext::alwaysAvailable(); bool isWithoutActuallyEscapingThunk = false; - bool isAsync = false; Inline_t inlineStrategy = InlineDefault; OptimizationMode optimizationMode = OptimizationMode::NotSet; SmallVector Semantics; @@ -5697,8 +5693,8 @@ bool SILParserState::parseDeclSIL(Parser &P) { &isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, &optimizationMode, nullptr, &isWeakImported, &availability, - &isWithoutActuallyEscapingThunk, &isAsync, &Semantics, &SpecAttrs, - &ClangDecl, &MRK, FunctionState, M) || + &isWithoutActuallyEscapingThunk, &Semantics, + &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) || P.parseToken(tok::at_sign, diag::expected_sil_function_name) || P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5736,7 +5732,6 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.F->setAvailabilityForLinkage(availability); FunctionState.F->setWithoutActuallyEscapingThunk( isWithoutActuallyEscapingThunk); - FunctionState.F->setAsync(isAsync); FunctionState.F->setInlineStrategy(inlineStrategy); FunctionState.F->setOptimizationMode(optimizationMode); FunctionState.F->setEffectsKind(MRK); @@ -5922,9 +5917,10 @@ bool SILParserState::parseSILGlobal(Parser &P) { SILParser State(P); if (parseSILLinkage(GlobalLinkage, P) || parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, State, M) || + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, + &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5973,7 +5969,7 @@ bool SILParserState::parseSILProperty(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, SP, M)) + nullptr, nullptr, nullptr, SP, M)) return true; ValueDecl *VD; @@ -6043,7 +6039,8 @@ bool SILParserState::parseSILVTable(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, VTableState, M)) + nullptr, nullptr, nullptr, + VTableState, M)) return true; // Parse the class name. @@ -6579,7 +6576,8 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, WitnessState, M)) + nullptr, nullptr, nullptr, + WitnessState, M)) return true; Scope S(&P, ScopeKind::TopLevel); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index d6524751b765f..b2cfae7bfd405 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -510,14 +510,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, + isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, + isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, @@ -625,11 +625,6 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, MF->fatal(); } - if (fn->isAsync() != isAsync) { - LLVM_DEBUG(llvm::dbgs() << "SILFunction type mismatch.\n"); - MF->fatal(); - } - } else { // Otherwise, create a new function. fn = builder.createDeclaration(name, ty, loc); @@ -638,7 +633,6 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setSerialized(IsSerialized_t(isSerialized)); fn->setThunk(IsThunk_t(isThunk)); fn->setWithoutActuallyEscapingThunk(bool(isWithoutactuallyEscapingThunk)); - fn->setAsync((bool)isAsync); fn->setInlineStrategy(Inline_t(inlineStrategy)); fn->setSpecialPurpose(SILFunction::Purpose(specialPurpose)); fn->setEffectsKind(EffectsKind(effect)); @@ -2829,14 +2823,14 @@ bool SILDeserializer::hasSILFunction(StringRef Name, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, + isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, + isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, optimizationMode, subclassScope, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index 1f572f01c127a..c1178d5f551ad 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -277,7 +277,6 @@ namespace sil_block { BCFixed<2>, // serialized BCFixed<2>, // thunks: signature optimized/reabstraction BCFixed<1>, // without_actually_escaping - BCFixed<1>, // async BCFixed<3>, // specialPurpose BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 74f658f3aaf6b..da46d36dd1b0a 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -433,7 +433,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.isSerialized(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), - (unsigned)F.isAsync(), (unsigned)F.getSpecialPurpose(), + (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), (unsigned)F.getClassSubclassScope(), (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), diff --git a/test/SILGen/async.swift b/test/SILGen/async.swift deleted file mode 100644 index 901978a7ac493..0000000000000 --- a/test/SILGen/async.swift +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %target-swift-frontend -emit-silgen -enable-experimental-concurrency -module-name Async -Xllvm -sil-full-demangle -parse-as-library %s | %FileCheck %s - -import Swift - -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async04testA0yyYF : $@convention(thin) () -> () { -func testAsync() async {} -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async11testAsyncp1SiyYF : $@convention(thin) () -> Int { -func testAsyncp1() async -> Int { return 0 } - -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test2yyYKF : $@convention(thin) () -> @error Error { -func test2() async throws {} -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test2p1SiyYKF : $@convention(thin) () -> (Int, @error Error) { -func test2p1() async throws -> Int { return 0 } - -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test3yyyyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> @error Error) -> @error Error { -func test3(_ cl: () throws -> ()) async rethrows {} -// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test3p1yS2iyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error) { -func test3p1(_ cl: () throws -> Int) async rethrows -> Int { return try cl() } - - From 9b8828848d3ed5a5ff90808146d008c94e3ac899 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 17 Aug 2020 16:40:00 -0700 Subject: [PATCH 248/663] [SIL] Add SILFunctionType flag for async. --- include/swift/AST/Attr.def | 1 + include/swift/AST/Types.h | 10 ++-- include/swift/SIL/SILFunction.h | 2 + lib/AST/ASTContext.cpp | 6 ++- lib/AST/ASTDemangler.cpp | 3 +- lib/AST/ASTPrinter.cpp | 7 +++ lib/AST/Type.cpp | 7 +-- lib/AST/TypeRepr.cpp | 3 ++ lib/IRGen/GenProto.cpp | 2 +- lib/IRGen/LoadableByAddress.cpp | 2 + lib/SIL/IR/SILBuilder.cpp | 1 + lib/SIL/IR/SILFunctionType.cpp | 52 ++++++++++--------- lib/SIL/IR/SILType.cpp | 5 +- lib/SIL/Verifier/SILVerifier.cpp | 1 + lib/SILGen/SILGen.cpp | 4 +- lib/SILGen/SILGenBridging.cpp | 2 +- lib/SILGen/SILGenExpr.cpp | 6 ++- lib/SILGen/SILGenFunction.cpp | 4 +- lib/SILGen/SILGenPoly.cpp | 6 +-- .../Differentiation/JVPCloner.cpp | 8 +-- lib/SILOptimizer/Differentiation/Thunk.cpp | 6 +-- .../Differentiation/VJPCloner.cpp | 8 +-- .../ExistentialTransform.cpp | 2 +- .../FunctionSignatureOpts.cpp | 9 ++-- lib/SILOptimizer/IPO/CapturePromotion.cpp | 5 +- lib/SILOptimizer/IPO/ClosureSpecializer.cpp | 2 +- .../Mandatory/Differentiation.cpp | 11 ++-- .../Transforms/AllocBoxToStack.cpp | 5 +- lib/SILOptimizer/Transforms/Outliner.cpp | 4 +- .../UtilityPasses/BugReducerTester.cpp | 3 +- lib/SILOptimizer/Utils/Generics.cpp | 11 ++-- lib/Sema/TypeCheckType.cpp | 18 +++++-- lib/Serialization/Deserialization.cpp | 5 +- lib/Serialization/ModuleFormat.h | 3 +- lib/Serialization/Serialization.cpp | 2 +- test/SIL/Parser/async.sil | 11 +++- test/SIL/Serialization/basic.sil | 4 +- 37 files changed, 153 insertions(+), 88 deletions(-) diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 660128379a139..2c744e4c0769a 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -53,6 +53,7 @@ TYPE_ATTR(noescape) TYPE_ATTR(escaping) TYPE_ATTR(differentiable) TYPE_ATTR(noDerivative) +TYPE_ATTR(async) // SIL-specific attributes TYPE_ATTR(block_storage) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 0f911f4fb5ae4..e3fbbd4e742c2 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -362,11 +362,12 @@ class alignas(1 << TypeAlignInBits) TypeBase { ID : 32 ); - SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2+1+1, + SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+1+2+1+1, ExtInfoBits : NumSILExtInfoBits, HasClangTypeInfo : 1, CalleeConvention : 3, HasErrorResult : 1, + IsAsync : 1, CoroutineKind : 2, HasInvocationSubs : 1, HasPatternSubs : 1 @@ -3979,7 +3980,7 @@ class SILFunctionType final + 1); } - SILFunctionType(GenericSignature genericSig, ExtInfo ext, + SILFunctionType(GenericSignature genericSig, ExtInfo ext, bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3993,7 +3994,8 @@ class SILFunctionType final public: static CanSILFunctionType - get(GenericSignature genericSig, ExtInfo ext, SILCoroutineKind coroutineKind, + get(GenericSignature genericSig, ExtInfo ext, bool isAsync, + SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef interfaceParams, ArrayRef interfaceYields, @@ -4046,6 +4048,8 @@ class SILFunctionType final return SILCoroutineKind(Bits.SILFunctionType.CoroutineKind); } + bool isAsync() const { return Bits.SILFunctionType.IsAsync; } + /// Return the array of all the yields. ArrayRef getYields() const { return const_cast(this)->getMutableYields(); diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index ae3f940d21ad4..5297539e43494 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -501,6 +501,8 @@ class SILFunction IsWithoutActuallyEscapingThunk = val; } + bool isAsync() const { return LoweredType->isAsync(); } + /// Returns the calling convention used by this entry point. SILFunctionTypeRepresentation getRepresentation() const { return getLoweredFunctionType()->getRepresentation(); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 830aed2cfe57a..ef19cd4d46b31 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3283,6 +3283,7 @@ void SILFunctionType::Profile( SILFunctionType::SILFunctionType( GenericSignature genericSig, ExtInfo ext, + bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3308,6 +3309,7 @@ SILFunctionType::SILFunctionType( "Bits were dropped!"); static_assert(SILExtInfoBuilder::NumMaskBits == NumSILExtInfoBits, "ExtInfo and SILFunctionTypeBitfields must agree on bit size"); + Bits.SILFunctionType.IsAsync = isAsync; Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind); NumParameters = params.size(); if (coroutineKind == SILCoroutineKind::None) { @@ -3451,7 +3453,7 @@ CanSILBlockStorageType SILBlockStorageType::get(CanType captureType) { CanSILFunctionType SILFunctionType::get( GenericSignature genericSig, - ExtInfo ext, SILCoroutineKind coroutineKind, + ExtInfo ext, bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention callee, ArrayRef params, ArrayRef yields, @@ -3518,7 +3520,7 @@ CanSILFunctionType SILFunctionType::get( } auto fnType = - new (mem) SILFunctionType(genericSig, ext, coroutineKind, callee, + new (mem) SILFunctionType(genericSig, ext, isAsync, coroutineKind, callee, params, yields, normalResults, errorResult, patternSubs, invocationSubs, ctx, properties, witnessMethodConformance); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 44d32c84a7a7d..6e44fd70da0ef 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -558,7 +558,8 @@ Type ASTBuilder::createImplFunctionType( auto conv = getResultConvention(errorResult->getConvention()); funcErrorResult.emplace(type, conv); } - return SILFunctionType::get(genericSig, einfo, funcCoroutineKind, + return SILFunctionType::get(genericSig, einfo, + /*isAsync*/ false, funcCoroutineKind, funcCalleeConvention, funcParams, funcYields, funcResults, funcErrorResult, SubstitutionMap(), SubstitutionMap(), Ctx); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 9423bf8506aa3..ed03d9a2c35c0 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4249,6 +4249,12 @@ class TypePrinter : public TypeVisitor { llvm_unreachable("bad convention"); } + void printSILAsyncAttr(bool isAsync) { + if (isAsync) { + Printer << "@async "; + } + } + void printCalleeConvention(ParameterConvention conv) { switch (conv) { case ParameterConvention::Direct_Unowned: @@ -4271,6 +4277,7 @@ class TypePrinter : public TypeVisitor { void visitSILFunctionType(SILFunctionType *T) { printSILCoroutineKind(T->getCoroutineKind()); + printSILAsyncAttr(T->isAsync()); printFunctionExtInfo(T->getASTContext(), T->getExtInfo(), T->getWitnessMethodConformanceOrInvalid()); printCalleeConvention(T->getCalleeConvention()); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index f26c9e39182af..bc7d9b780b659 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4378,6 +4378,7 @@ case TypeKind::Id: return SILFunctionType::get( fnTy->getInvocationGenericSignature(), fnTy->getExtInfo(), + fnTy->isAsync(), fnTy->getCoroutineKind(), fnTy->getCalleeConvention(), transInterfaceParams, @@ -5371,7 +5372,7 @@ SILFunctionType::withInvocationSubstitutions(SubstitutionMap subs) const { assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getInvocationGenericSignature()); return SILFunctionType::get(getInvocationGenericSignature(), - getExtInfo(), getCoroutineKind(), + getExtInfo(), isAsync(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), @@ -5389,7 +5390,7 @@ SILFunctionType::withPatternSubstitutions(SubstitutionMap subs) const { assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getPatternGenericSignature()); return SILFunctionType::get(getInvocationGenericSignature(), - getExtInfo(), getCoroutineKind(), + getExtInfo(), isAsync(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), @@ -5408,7 +5409,7 @@ SILFunctionType::withPatternSpecialization(CanGenericSignature sig, assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getSubstGenericSignature()); return SILFunctionType::get(sig, - getExtInfo(), getCoroutineKind(), + getExtInfo(), isAsync(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index bb7e6e65f74e5..6490258e3b922 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -171,6 +171,9 @@ void AttributedTypeRepr::printAttrs(ASTPrinter &Printer, Printer.printStructurePost(PrintStructureKind::BuiltinAttribute); Printer << " "; } + + if (hasAttr(TAK_async)) + Printer.printSimpleAttr("@async") << " "; } IdentTypeRepr *IdentTypeRepr::create(ASTContext &C, diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 2795553485a5a..6282e402545c8 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3056,7 +3056,7 @@ GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, // Construct a representative function type. auto generics = ncGenerics.getCanonicalSignature(); auto fnType = SILFunctionType::get(generics, SILFunctionType::ExtInfo(), - SILCoroutineKind::None, + /*isAsync*/ false, SILCoroutineKind::None, /*callee*/ ParameterConvention::Direct_Unowned, /*params*/ {}, /*yields*/ {}, /*results*/ {}, /*error*/ None, diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 2a509cbfeeb89..6d798d7ea8131 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -297,6 +297,7 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env, auto newFnType = SILFunctionType::get( fnType->getInvocationGenericSignature(), fnType->getExtInfo(), + fnType->isAsync(), fnType->getCoroutineKind(), fnType->getCalleeConvention(), newParams, @@ -2361,6 +2362,7 @@ static bool rewriteFunctionReturn(StructLoweringState &pass) { auto NewTy = SILFunctionType::get( loweredTy->getSubstGenericSignature(), loweredTy->getExtInfo(), + loweredTy->isAsync(), loweredTy->getCoroutineKind(), loweredTy->getCalleeConvention(), loweredTy->getParameters(), diff --git a/lib/SIL/IR/SILBuilder.cpp b/lib/SIL/IR/SILBuilder.cpp index c925cc83bb737..d6a876037c0b9 100644 --- a/lib/SIL/IR/SILBuilder.cpp +++ b/lib/SIL/IR/SILBuilder.cpp @@ -107,6 +107,7 @@ SILType SILBuilder::getPartialApplyResultType( auto appliedFnType = SILFunctionType::get(nullptr, extInfo, + FTI->isAsync(), FTI->getCoroutineKind(), calleeConvention, newParams, diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 2d3e10054313d..0e50bdd34f8e4 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -94,6 +94,7 @@ CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const { : CanGenericSignature(); return SILFunctionType::get(signature, getExtInfo(), + isAsync(), getCoroutineKind(), getCalleeConvention(), params, yields, results, errorResult, @@ -287,11 +288,11 @@ SILFunctionType::getWithDifferentiability(DifferentiabilityKind kind, } auto newExtInfo = getExtInfo().intoBuilder().withDifferentiabilityKind(kind).build(); - return get(getInvocationGenericSignature(), newExtInfo, getCoroutineKind(), - getCalleeConvention(), newParameters, getYields(), newResults, - getOptionalErrorResult(), getPatternSubstitutions(), - getInvocationSubstitutions(), getASTContext(), - getWitnessMethodConformanceOrInvalid()); + return get(getInvocationGenericSignature(), newExtInfo, isAsync(), + getCoroutineKind(), getCalleeConvention(), newParameters, + getYields(), newResults, getOptionalErrorResult(), + getPatternSubstitutions(), getInvocationSubstitutions(), + getASTContext(), getWitnessMethodConformanceOrInvalid()); } CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { @@ -311,9 +312,9 @@ CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { newResults.push_back(result.getWithDifferentiability( SILResultDifferentiability::DifferentiableOrNotApplicable)); return SILFunctionType::get( - getInvocationGenericSignature(), nondiffExtInfo, getCoroutineKind(), - getCalleeConvention(), newParams, getYields(), newResults, - getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationGenericSignature(), nondiffExtInfo, isAsync(), + getCoroutineKind(), getCalleeConvention(), newParams, getYields(), + newResults, getOptionalErrorResult(), getPatternSubstitutions(), getInvocationSubstitutions(), getASTContext()); } @@ -502,9 +503,9 @@ static CanSILFunctionType getAutoDiffDifferentialType( llvm::makeArrayRef(substConformances)); } return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, - ParameterConvention::Direct_Guaranteed, differentialParams, {}, - differentialResults, None, substitutions, + GenericSignature(), SILFunctionType::ExtInfo(), /*isAsync*/ false, + SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, + differentialParams, {}, differentialResults, None, substitutions, /*invocationSubstitutions*/ SubstitutionMap(), ctx); } @@ -681,9 +682,9 @@ static CanSILFunctionType getAutoDiffPullbackType( llvm::makeArrayRef(substConformances)); } return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, - ParameterConvention::Direct_Guaranteed, pullbackParams, {}, - pullbackResults, None, substitutions, + GenericSignature(), SILFunctionType::ExtInfo(), /*isAsync*/ false, + SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, + pullbackParams, {}, pullbackResults, None, substitutions, /*invocationSubstitutions*/ SubstitutionMap(), ctx); } @@ -737,7 +738,7 @@ static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( constrainedInvocationGenSig->areAllParamsConcrete() ? GenericSignature() : constrainedInvocationGenSig, - original->getExtInfo(), original->getCoroutineKind(), + original->getExtInfo(), original->isAsync(), original->getCoroutineKind(), original->getCalleeConvention(), newParameters, original->getYields(), newResults, original->getOptionalErrorResult(), /*patternSubstitutions*/ SubstitutionMap(), @@ -828,6 +829,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( // cache and return. cachedResult = SILFunctionType::get( constrainedOriginalFnTy->getSubstGenericSignature(), extInfo, + constrainedOriginalFnTy->isAsync(), constrainedOriginalFnTy->getCoroutineKind(), constrainedOriginalFnTy->getCalleeConvention(), newParameters, constrainedOriginalFnTy->getYields(), newResults, @@ -913,9 +915,9 @@ CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( for (auto &res : getResults()) newParameters.push_back(getParameterInfoForOriginalResult(res)); return SILFunctionType::get( - getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), - getCalleeConvention(), newParameters, getYields(), newResults, - getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationGenericSignature(), getExtInfo(), isAsync(), + getCoroutineKind(), getCalleeConvention(), newParameters, getYields(), + newResults, getOptionalErrorResult(), getPatternSubstitutions(), /*invocationSubstitutions*/ {}, getASTContext()); } @@ -989,7 +991,8 @@ Lowering::adjustFunctionType(CanSILFunctionType type, return type; return SILFunctionType::get(type->getInvocationGenericSignature(), - extInfo, type->getCoroutineKind(), callee, + extInfo, type->isAsync(), + type->getCoroutineKind(), callee, type->getParameters(), type->getYields(), type->getResults(), type->getOptionalErrorResult(), @@ -1016,9 +1019,9 @@ CanSILFunctionType SILFunctionType::getWithExtInfo(ExtInfo newExt) { : Lowering::DefaultThickCalleeConvention) : ParameterConvention::Direct_Unowned); - return get(getInvocationGenericSignature(), newExt, getCoroutineKind(), - calleeConvention, getParameters(), getYields(), getResults(), - getOptionalErrorResult(), getPatternSubstitutions(), + return get(getInvocationGenericSignature(), newExt, isAsync(), + getCoroutineKind(), calleeConvention, getParameters(), getYields(), + getResults(), getOptionalErrorResult(), getPatternSubstitutions(), getInvocationSubstitutions(), getASTContext(), getWitnessMethodConformanceOrInvalid()); } @@ -2166,7 +2169,8 @@ static CanSILFunctionType getSILFunctionType( } } - return SILFunctionType::get(genericSig, silExtInfo, coroutineKind, + return SILFunctionType::get(genericSig, silExtInfo, + substFnInterfaceType->isAsync(), coroutineKind, calleeConvention, inputs, yields, results, errorResult, substitutions, SubstitutionMap(), @@ -3756,7 +3760,7 @@ class SILTypeSubstituter : ? origType->getInvocationGenericSignature() : nullptr; - return SILFunctionType::get(genericSig, extInfo, + return SILFunctionType::get(genericSig, extInfo, origType->isAsync(), origType->getCoroutineKind(), origType->getCalleeConvention(), substParams, substYields, substResults, substErrorResult, diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index 48ca1e5cbc47d..28f323ccf8769 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -671,9 +671,10 @@ TypeBase::replaceSubstitutedSILFunctionTypesWithUnsubstituted(SILModule &M) cons if (!didChange) return sft; - + return SILFunctionType::get(sft->getInvocationGenericSignature(), - sft->getExtInfo(), sft->getCoroutineKind(), + sft->getExtInfo(), sft->isAsync(), + sft->getCoroutineKind(), sft->getCalleeConvention(), newParams, newYields, newResults, newErrorResult, diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index c2f3de4038027..3f27e20fe801d 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -3003,6 +3003,7 @@ class SILVerifier : public SILVerifierBase { auto fnTy = SILFunctionType::get(nullptr, methodTy->getExtInfo(), + methodTy->isAsync(), methodTy->getCoroutineKind(), methodTy->getCalleeConvention(), dynParams, diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index cd36b343f0e58..dffd4c3b8dfdf 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -419,7 +419,7 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, /*clangFunctionType*/ nullptr) .build(); - auto functionTy = SILFunctionType::get(sig, extInfo, + auto functionTy = SILFunctionType::get(sig, extInfo, /*isAsync*/ false, SILCoroutineKind::YieldOnce, ParameterConvention::Direct_Unowned, params, @@ -482,7 +482,7 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) { }; CanSILFunctionType topLevelType = SILFunctionType::get(nullptr, extInfo, - SILCoroutineKind::None, + /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, SILResultInfo(Int32Ty, diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 7eedc3b1975fa..a013d5b188baa 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -578,7 +578,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, } auto invokeTy = SILFunctionType::get( - genericSig, extInfo, SILCoroutineKind::None, + genericSig, extInfo, /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, blockInterfaceTy->getResults(), blockInterfaceTy->getOptionalErrorResult(), diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index cb8273d129e1e..8ef8f36c118ee 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2750,6 +2750,7 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, return SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), + /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, result, None, @@ -2896,9 +2897,10 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredInterfaceType() ->getCanonicalType(), ParameterConvention::Direct_Unowned}); - + return SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), + /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, {}, None, @@ -3081,6 +3083,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), + /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, @@ -3255,6 +3258,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), + /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index d9acdc516f6ac..7f6cf2516db66 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -602,6 +602,7 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { SILFunctionType::ExtInfo() .withRepresentation(SILFunctionType::Representation:: CFunctionPointer), + /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, SILParameterInfo(anyObjectMetaTy, @@ -697,7 +698,8 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { // has an overlay to fix the type of argv. .withRepresentation(SILFunctionType::Representation::Thin) .build(), - SILCoroutineKind::None, ParameterConvention::Direct_Unowned, argTypes, + /*isAsync*/ false, SILCoroutineKind::None, + ParameterConvention::Direct_Unowned, argTypes, /*yields*/ {}, SILResultInfo(argc->getType().getASTType(), ResultConvention::Unowned), /*error result*/ None, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 0ee11d74f6439..110edd25ba171 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -3245,9 +3245,9 @@ CanSILFunctionType SILGenFunction::buildThunkType( // The type of the thunk function. return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), - ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, - interfaceResults, interfaceErrorResult, + genericSig, extInfoBuilder.build(), expectedType->isAsync(), + expectedType->getCoroutineKind(), ParameterConvention::Direct_Unowned, + interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, expectedType->getPatternSubstitutions(), SubstitutionMap(), getASTContext()); } diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index 8152f409d7592..b6df19215ba4d 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -1587,10 +1587,10 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto *diffGenericEnv = diffGenericSig ? diffGenericSig->getGenericEnvironment() : nullptr; auto diffType = SILFunctionType::get( - diffGenericSig, origTy->getExtInfo(), origTy->getCoroutineKind(), - origTy->getCalleeConvention(), dfParams, {}, dfResults, None, - origTy->getPatternSubstitutions(), origTy->getInvocationSubstitutions(), - original->getASTContext()); + diffGenericSig, origTy->getExtInfo(), origTy->isAsync(), + origTy->getCoroutineKind(), origTy->getCalleeConvention(), dfParams, {}, + dfResults, None, origTy->getPatternSubstitutions(), + origTy->getInvocationSubstitutions(), original->getASTContext()); SILOptFunctionBuilder fb(context.getTransform()); auto linkage = jvp->isSerialized() ? SILLinkage::Public : SILLinkage::Hidden; diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index 820805fff06d9..bd1817c6f3994 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -242,9 +242,9 @@ CanSILFunctionType buildThunkType(SILFunction *fn, // The type of the thunk function. return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), - ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, - interfaceResults, interfaceErrorResult, + genericSig, extInfoBuilder.build(), expectedType->isAsync(), + expectedType->getCoroutineKind(), ParameterConvention::Direct_Unowned, + interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, expectedType->getPatternSubstitutions(), SubstitutionMap(), fn->getASTContext()); } diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index 186173e025bc3..c3037cdb76693 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -893,10 +893,10 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { auto *pbGenericEnv = pbGenericSig ? pbGenericSig->getGenericEnvironment() : nullptr; auto pbType = SILFunctionType::get( - pbGenericSig, origTy->getExtInfo(), origTy->getCoroutineKind(), - origTy->getCalleeConvention(), pbParams, {}, adjResults, None, - origTy->getPatternSubstitutions(), origTy->getInvocationSubstitutions(), - original->getASTContext()); + pbGenericSig, origTy->getExtInfo(), origTy->isAsync(), + origTy->getCoroutineKind(), origTy->getCalleeConvention(), pbParams, {}, + adjResults, None, origTy->getPatternSubstitutions(), + origTy->getInvocationSubstitutions(), original->getASTContext()); SILOptFunctionBuilder fb(context.getTransform()); auto linkage = vjp->isSerialized() ? SILLinkage::Public : SILLinkage::Private; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 66617c63b0c24..839810a36223d 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -403,7 +403,7 @@ ExistentialTransform::createExistentialSpecializedFunctionType() { /// Return the new signature. return SILFunctionType::get( - NewGenericSig, ExtInfo, FTy->getCoroutineKind(), + NewGenericSig, ExtInfo, FTy->isAsync(), FTy->getCoroutineKind(), FTy->getCalleeConvention(), InterfaceParams, FTy->getYields(), FTy->getResults(), InterfaceErrorResult, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 7d1f34ea07cc4..328f55ab17ee9 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -408,10 +408,11 @@ FunctionSignatureTransformDescriptor::createOptimizedSILFunctionType() { UsesGenerics ? FTy->getInvocationGenericSignature() : nullptr; return SILFunctionType::get( - GenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(), - InterfaceParams, InterfaceYields, InterfaceResults, InterfaceErrorResult, - FTy->getPatternSubstitutions(), SubstitutionMap(), - F->getModule().getASTContext(), witnessMethodConformance); + GenericSig, ExtInfo, FTy->isAsync(), FTy->getCoroutineKind(), + FTy->getCalleeConvention(), InterfaceParams, InterfaceYields, + InterfaceResults, InterfaceErrorResult, FTy->getPatternSubstitutions(), + SubstitutionMap(), F->getModule().getASTContext(), + witnessMethodConformance); } /// Compute what the function interface will look like based on the diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp index 37533fef306fc..ee4f6badc8505 100644 --- a/lib/SILOptimizer/IPO/CapturePromotion.cpp +++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp @@ -428,8 +428,9 @@ ClosureCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, // Create the thin function type for the cloned closure. auto ClonedTy = SILFunctionType::get( OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), - OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), - ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), + OrigFTI->isAsync(), OrigFTI->getCoroutineKind(), + OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, + OrigFTI->getYields(), OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 05ab7bcaf6f10..137054e99ec18 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -670,7 +670,7 @@ ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, auto ClonedTy = SILFunctionType::get( ClosureUserFunTy->getInvocationGenericSignature(), ExtInfo, - ClosureUserFunTy->getCoroutineKind(), + ClosureUserFunTy->isAsync(), ClosureUserFunTy->getCoroutineKind(), ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList, ClosureUserFunTy->getYields(), ClosureUserFunTy->getResults(), ClosureUserFunTy->getOptionalErrorResult(), diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 083f840e892e7..a2e60703933bf 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -872,7 +872,8 @@ static void emitFatalError(ADContext &context, SILFunction *f, // Fatal error function must have type `@convention(thin) () -> Never`. auto fatalErrorFnType = SILFunctionType::get( /*genericSig*/ nullptr, SILFunctionType::ExtInfo::getThin(), - SILCoroutineKind::None, ParameterConvention::Direct_Unowned, {}, + /*isAsync*/ false, SILCoroutineKind::None, + ParameterConvention::Direct_Unowned, {}, /*interfaceYields*/ {}, neverResultInfo, /*interfaceErrorResults*/ None, {}, {}, context.getASTContext()); auto fnBuilder = SILOptFunctionBuilder(context.getTransform()); @@ -1024,10 +1025,10 @@ static SILValue promoteCurryThunkApplicationToDifferentiableFunction( auto newThunkResult = thunkResult.getWithInterfaceType(diffResultFnTy); auto thunkType = SILFunctionType::get( thunkTy->getSubstGenericSignature(), thunkTy->getExtInfo(), - thunkTy->getCoroutineKind(), thunkTy->getCalleeConvention(), - thunkTy->getParameters(), {}, {newThunkResult}, {}, - thunkTy->getPatternSubstitutions(), thunkTy->getInvocationSubstitutions(), - thunkTy->getASTContext()); + thunkTy->isAsync(), thunkTy->getCoroutineKind(), + thunkTy->getCalleeConvention(), thunkTy->getParameters(), {}, + {newThunkResult}, {}, thunkTy->getPatternSubstitutions(), + thunkTy->getInvocationSubstitutions(), thunkTy->getASTContext()); // Construct new curry thunk, returning a `@differentiable` function. SILOptFunctionBuilder fb(dt.getTransform()); diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 6483b47a12a6f..93571944f8312 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -699,8 +699,9 @@ SILFunction *PromotedParamCloner::initCloned(SILOptFunctionBuilder &FuncBuilder, // the parameters promoted. auto ClonedTy = SILFunctionType::get( OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), - OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), - ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), + OrigFTI->isAsync(), OrigFTI->getCoroutineKind(), + OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, + OrigFTI->getYields(), OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(), OrigFTI->getPatternSubstitutions(), OrigFTI->getInvocationSubstitutions(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index e052a6b000f3c..4426205c94ff0 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -302,7 +302,7 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { /*clangFunctionType*/ nullptr) .build(); auto FunctionType = SILFunctionType::get( - nullptr, ExtInfo, SILCoroutineKind::None, + nullptr, ExtInfo, /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, /*yields*/ {}, Results, None, SubstitutionMap(), SubstitutionMap(), @@ -1203,7 +1203,7 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { SILResultInfo(BridgedReturn.getReturnType(), ResultConvention::Owned)); } auto FunctionType = SILFunctionType::get( - nullptr, ExtInfo, SILCoroutineKind::None, + nullptr, ExtInfo, /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, {}, Results, None, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index a8f823e584d5a..3ec8f130c3496 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -89,7 +89,8 @@ class BugReducerTester : public SILFunctionTransform { false /*noescape*/, DifferentiabilityKind::NonDifferentiable, nullptr /*clangFunctionType*/) .build(), - SILCoroutineKind::None, ParameterConvention::Direct_Unowned, + /*isAsync*/ false, SILCoroutineKind::None, + ParameterConvention::Direct_Unowned, ArrayRef(), ArrayRef(), ResultInfoArray, None, SubstitutionMap(), SubstitutionMap(), getFunction()->getModule().getASTContext()); diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 2bde614efd66c..39dfd0c59c28f 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -785,10 +785,11 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, // Use the new specialized generic signature. auto NewFnTy = SILFunctionType::get( - CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCoroutineKind(), - FnTy->getCalleeConvention(), FnTy->getParameters(), FnTy->getYields(), - FnTy->getResults(), FnTy->getOptionalErrorResult(), - FnTy->getPatternSubstitutions(), SubstitutionMap(), M.getASTContext(), + CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->isAsync(), + FnTy->getCoroutineKind(), FnTy->getCalleeConvention(), + FnTy->getParameters(), FnTy->getYields(), FnTy->getResults(), + FnTy->getOptionalErrorResult(), FnTy->getPatternSubstitutions(), + SubstitutionMap(), M.getASTContext(), FnTy->getWitnessMethodConformanceOrInvalid()); // This is an interface type. It should not have any archetypes. @@ -856,7 +857,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const { ? SubstFTy->getInvocationGenericSignature() : CanGenericSignature(); return SILFunctionType::get( - Signature, SubstFTy->getExtInfo(), + Signature, SubstFTy->getExtInfo(), SubstFTy->isAsync(), SubstFTy->getCoroutineKind(), SubstFTy->getCalleeConvention(), SpecializedParams, SpecializedYields, SpecializedResults, SubstFTy->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 2cd63edbe1563..864d2b926adb9 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1749,6 +1749,7 @@ namespace { Type resolveSILFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, + bool isAsync = false, SILCoroutineKind coroutineKind = SILCoroutineKind::None, SILFunctionType::ExtInfo extInfo @@ -2078,7 +2079,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, static const TypeAttrKind FunctionAttrs[] = { TAK_convention, TAK_pseudogeneric, TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape, TAK_autoclosure, - TAK_differentiable, TAK_escaping, TAK_yield_once, TAK_yield_many + TAK_differentiable, TAK_escaping, TAK_yield_once, TAK_yield_many, TAK_async }; auto checkUnsupportedAttr = [&](TypeAttrKind attr) { @@ -2146,6 +2147,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, SILFunctionType::Representation rep; TypeRepr *witnessMethodProtocol = nullptr; + auto isAsync = attrs.has(TAK_async); + auto coroutineKind = SILCoroutineKind::None; if (attrs.has(TAK_yield_once)) { coroutineKind = SILCoroutineKind::YieldOnce; @@ -2227,7 +2230,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, attrs.has(TAK_noescape), diffKind, nullptr) .build(); - ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, + ty = resolveSILFunctionType(fnRepr, options, isAsync, coroutineKind, extInfo, calleeConvention, witnessMethodProtocol); if (!ty || ty->hasError()) return ty; @@ -2470,6 +2473,13 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, attrs.clearAttribute(TAK_dynamic_self); } + // In SIL *only*, allow @async to specify an async function + if ((options & TypeResolutionFlags::SILMode) && attrs.has(TAK_async)) { + if (fnRepr != nullptr) { + attrs.clearAttribute(TAK_async); + } + } + for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i) if (attrs.has((TypeAttrKind)i)) { diagnoseInvalid(repr, attrs.getLoc((TypeAttrKind)i), @@ -2835,6 +2845,7 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, + bool isAsync, SILCoroutineKind coroutineKind, SILFunctionType::ExtInfo extInfo, ParameterConvention callee, @@ -3029,7 +3040,8 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, "found witness_method without matching conformance"); } - return SILFunctionType::get(genericSig, extInfo, coroutineKind, callee, + return SILFunctionType::get(genericSig, extInfo, isAsync, + coroutineKind, callee, interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, interfacePatternSubs, invocationSubs, diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index ec8645447d5b3..f56c3cad967e2 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5355,6 +5355,7 @@ class TypeDeserializer { Expected deserializeSILFunctionType(ArrayRef scratch, StringRef blobData) { + bool async; uint8_t rawCoroutineKind; uint8_t rawCalleeConvention; uint8_t rawRepresentation; @@ -5372,6 +5373,7 @@ class TypeDeserializer { ClangTypeID clangFunctionTypeID; decls_block::SILFunctionTypeLayout::readRecord(scratch, + async, rawCoroutineKind, rawCalleeConvention, rawRepresentation, @@ -5561,7 +5563,8 @@ class TypeDeserializer { if (!patternSubsOrErr) return patternSubsOrErr.takeError(); - return SILFunctionType::get(invocationSig, extInfo, coroutineKind.getValue(), + return SILFunctionType::get(invocationSig, extInfo, + async, coroutineKind.getValue(), calleeConvention.getValue(), allParams, allYields, allResults, errorResult, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 7a8364d7852c1..0c6bc3f61564e 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 572; // revert isUserAccessible +const uint16_t SWIFTMODULE_VERSION_MINOR = 573; // @async on SILFunctionType /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1049,6 +1049,7 @@ namespace decls_block { using SILFunctionTypeLayout = BCRecordLayout< SIL_FUNCTION_TYPE, + BCFixed<1>, // async? SILCoroutineKindField, // coroutine kind ParameterConventionField, // callee convention SILFunctionTypeRepresentationField, // representation diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8c5cd273a7e3b..4e099c13de728 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -4232,7 +4232,7 @@ class Serializer::TypeSerializer : public TypeVisitor { unsigned abbrCode = S.DeclTypeAbbrCodes[SILFunctionTypeLayout::Code]; SILFunctionTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, - stableCoroutineKind, stableCalleeConvention, + fnTy->isAsync(), stableCoroutineKind, stableCalleeConvention, stableRepresentation, fnTy->isPseudogeneric(), fnTy->isNoEscape(), stableDiffKind, fnTy->hasErrorResult(), fnTy->getParameters().size(), fnTy->getNumYields(), fnTy->getNumResults(), diff --git a/test/SIL/Parser/async.sil b/test/SIL/Parser/async.sil index 694f66de78175..374572412f494 100644 --- a/test/SIL/Parser/async.sil +++ b/test/SIL/Parser/async.sil @@ -1,8 +1,15 @@ // RUN: %target-sil-opt -enable-sil-verify-all=true %s | %target-sil-opt -enable-sil-verify-all=true | %FileCheck %s -// CHECK: sil [async] @async_test -sil [async] @async_test : $() -> () { +// CHECK: sil @async_test : $@async +sil @async_test : $@async () -> () { bb0: %0 = tuple () return %0 : $() } + +// CHECK: sil @take_async : $@convention(thin) (@async () -> ()) -> () +sil @take_async : $(@async () -> ()) -> () { +bb0(%fn : $@async () -> ()): + %0 = tuple () + return %0 : $() +} diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil index dd7f9ba3a54d4..1d9f1de1a810e 100644 --- a/test/SIL/Serialization/basic.sil +++ b/test/SIL/Serialization/basic.sil @@ -15,8 +15,8 @@ bb0(%0 : @guaranteed $Builtin.NativeObject): return undef : $() } -// CHECK-LABEL: sil [async] @async_test -sil [async] @async_test : $() -> () { +// CHECK-LABEL: sil @async_test : $@async @convention(thin) +sil @async_test : $@async () -> () { bb0: %0 = tuple () return %0 : $() From a90d63df4955f884336f27886d0a251dd7c2bb19 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 18 Aug 2020 14:55:24 -0700 Subject: [PATCH 249/663] [NFC] Add PrettyStackTraces to ObjC forward decls Helps identify the cause of some crashes. --- lib/PrintAsObjC/ModuleContentsWriter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/PrintAsObjC/ModuleContentsWriter.cpp b/lib/PrintAsObjC/ModuleContentsWriter.cpp index ba703f28937cc..da579b24a3f99 100644 --- a/lib/PrintAsObjC/ModuleContentsWriter.cpp +++ b/lib/PrintAsObjC/ModuleContentsWriter.cpp @@ -16,6 +16,7 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Module.h" +#include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SwiftNameTranslation.h" #include "swift/AST/TypeDeclFinder.h" @@ -235,6 +236,8 @@ class ModuleWriter { } bool forwardDeclareMemberTypes(DeclRange members, const Decl *container) { + PrettyStackTraceDecl + entry("printing forward declarations needed by members of", container); switch (container->getKind()) { case DeclKind::Class: case DeclKind::Protocol: @@ -247,6 +250,7 @@ class ModuleWriter { bool hadAnyDelayedMembers = false; SmallVector nestedTypes; for (auto member : members) { + PrettyStackTraceDecl loopEntry("printing for member", member); auto VD = dyn_cast(member); if (!VD || !printer.shouldInclude(VD)) continue; @@ -269,6 +273,8 @@ class ModuleWriter { ReferencedTypeFinder::walk(VD->getInterfaceType(), [&](ReferencedTypeFinder &finder, const TypeDecl *TD) { + PrettyStackTraceDecl + entry("walking its interface type, currently at", TD); if (TD == container) return; From a60aad89a7b2dc04f73c17367448160a1645d359 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 18 Aug 2020 16:42:15 -0700 Subject: [PATCH 250/663] [PrintAsObjC] Forward-declare bridged types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The initial pass through a type’s members to forward-declare or import anything needed by them did not account for _ObjectiveCBridgeable conformances; instead, it would examine the Swift type being bridged from, either tripping an assertion or just failing to do anything. Treat these as references to the bridged type instead. Fixes rdar://67263753. --- lib/PrintAsObjC/DeclAndTypePrinter.cpp | 10 ++++++++++ lib/PrintAsObjC/DeclAndTypePrinter.h | 8 ++++++++ lib/PrintAsObjC/ModuleContentsWriter.cpp | 3 +++ test/PrintAsObjC/classes.swift | 22 ++++++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index b848f04627854..4653c9c1293c8 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -1339,6 +1339,7 @@ class DeclAndTypePrinter::Implementation return true; } +public: /// If \p nominal is bridged to an Objective-C class (via a conformance to /// _ObjectiveCBridgeable), return that class. /// @@ -1369,6 +1370,7 @@ class DeclAndTypePrinter::Implementation return objcType->getClassOrBoundGenericClass(); } +private: /// If the nominal type is bridged to Objective-C (via a conformance /// to _ObjectiveCBridgeable), print the bridged type. void printObjCBridgeableType(const NominalTypeDecl *swiftNominal, @@ -2067,6 +2069,14 @@ bool DeclAndTypePrinter::isEmptyExtensionDecl(const ExtensionDecl *ED) { return getImpl().isEmptyExtensionDecl(ED); } +const TypeDecl *DeclAndTypePrinter::getObjCTypeDecl(const TypeDecl* TD) { + if (auto *nominal = dyn_cast(TD)) + if (auto *bridged = getImpl().getObjCBridgedClass(nominal)) + return bridged; + + return TD; +} + StringRef DeclAndTypePrinter::maybeGetOSObjectBaseName(const clang::NamedDecl *decl) { StringRef name = decl->getName(); diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.h b/lib/PrintAsObjC/DeclAndTypePrinter.h index 933f2ea16a859..c7718faac3e6b 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.h +++ b/lib/PrintAsObjC/DeclAndTypePrinter.h @@ -73,6 +73,14 @@ class DeclAndTypePrinter { /// Is \p ED empty of members and protocol conformances to include? bool isEmptyExtensionDecl(const ExtensionDecl *ED); + /// Returns the type that will be printed by PrintAsObjC for a parameter or + /// result type resolved to this declaration. + /// + /// \warning This handles \c _ObjectiveCBridgeable types, but it doesn't + /// currently know about other aspects of PrintAsObjC behavior, like known + /// types. + const TypeDecl *getObjCTypeDecl(const TypeDecl* TD); + /// Prints a category declaring the given members. /// /// All members must have the same parent type. The list must not be empty. diff --git a/lib/PrintAsObjC/ModuleContentsWriter.cpp b/lib/PrintAsObjC/ModuleContentsWriter.cpp index da579b24a3f99..135cabf70ea5d 100644 --- a/lib/PrintAsObjC/ModuleContentsWriter.cpp +++ b/lib/PrintAsObjC/ModuleContentsWriter.cpp @@ -278,6 +278,9 @@ class ModuleWriter { if (TD == container) return; + // Bridge, if necessary. + TD = printer.getObjCTypeDecl(TD); + if (finder.needsDefinition() && isa(TD)) { // We can delay individual members of classes; do so if necessary. if (isa(container)) { diff --git a/test/PrintAsObjC/classes.swift b/test/PrintAsObjC/classes.swift index 025bef7fb4d5d..55b6b7edaccd5 100644 --- a/test/PrintAsObjC/classes.swift +++ b/test/PrintAsObjC/classes.swift @@ -49,8 +49,26 @@ import SingleGenericClass // CHECK-NEXT: @end @objc class B1 : A1 {} +// Used in BridgedTypes test case +struct Notification: _ObjectiveCBridgeable { + func _bridgeToObjectiveC() -> NSNotification { fatalError() } + static func _forceBridgeFromObjectiveC( + _ source: NSNotification, + result: inout Self? + ) { fatalError() } + @discardableResult + static func _conditionallyBridgeFromObjectiveC( + _ source: NSNotification, + result: inout Self? + ) -> Bool { fatalError() } + @_effects(readonly) + static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) + -> Self { fatalError() } +} + // CHECK-LABEL: @interface BridgedTypes // CHECK-NEXT: - (NSDictionary * _Nonnull)dictBridge:(NSDictionary * _Nonnull)x SWIFT_WARN_UNUSED_RESULT; +// CHECK-NEXT: - (NSNotification * _Nonnull)noteBridge:(NSNotification * _Nonnull)x SWIFT_WARN_UNUSED_RESULT; // CHECK-NEXT: - (NSSet * _Nonnull)setBridge:(NSSet * _Nonnull)x SWIFT_WARN_UNUSED_RESULT; // CHECK-NEXT: init // CHECK-NEXT: @end @@ -59,6 +77,10 @@ import SingleGenericClass return x } + @objc func noteBridge(_ x: Notification) -> Notification { + return x + } + @objc func setBridge(_ x: Set) -> Set { return x } From e2a1862870e6bc451abff445a14c087ead3439ff Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Wed, 19 Aug 2020 17:05:52 -0700 Subject: [PATCH 251/663] [AutoDiff upstream] Add `inout` parameter differentiation tests. (#33555) --- .../validation-test/inout_parameters.swift | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/test/AutoDiff/validation-test/inout_parameters.swift b/test/AutoDiff/validation-test/inout_parameters.swift index 4cbd25590b943..626546040a900 100644 --- a/test/AutoDiff/validation-test/inout_parameters.swift +++ b/test/AutoDiff/validation-test/inout_parameters.swift @@ -1,11 +1,174 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test +// `inout` parameter differentiation tests. + import DifferentiationUnittest import StdlibUnittest var InoutParameterAutoDiffTests = TestSuite("InoutParameterDifferentiation") +// TODO(TF-1173): Move floating-point mutating operation tests to +// `test/AutoDiff/stdlib/floating_point.swift.gyb` when forward-mode +// differentiation supports `inout` parameter differentiation. + +InoutParameterAutoDiffTests.test("Float.+=") { + func mutatingAddWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingAddWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingAddWrapper)(10)) +} + +InoutParameterAutoDiffTests.test("Float.-=") { + func mutatingSubtractWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingSubtractWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingSubtractWrapper)(10)) +} + +InoutParameterAutoDiffTests.test("Float.*=") { + func mutatingMultiplyWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingMultiplyWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingMultiplyWrapper)(10)) +} + +InoutParameterAutoDiffTests.test("Float./=") { + func mutatingDivideWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual((1, 1), gradient(at: 4, 5, in: mutatingDivideWrapper)) + expectEqual((10, 10), pullback(at: 4, 5, in: mutatingDivideWrapper)(10)) +} + +// Simplest possible `inout` parameter differentiation. +InoutParameterAutoDiffTests.test("InoutIdentity") { + // Semantically, an empty function with an `inout` parameter is an identity + // function. + func inoutIdentity(_ x: inout Float) {} + + func identity(_ x: Float) -> Float { + var result = x + inoutIdentity(&result) + return result + } + expectEqual(1, gradient(at: 10, in: identity)) + expectEqual(10, pullback(at: 10, in: identity)(10)) +} + +extension Float { + // Custom version of `Float.*=`, implemented using `Float.*` and mutation. + // Verify that its generated derivative has the same behavior as the + // registered derivative for `Float.*=`. + @differentiable + static func multiplyAssign(_ lhs: inout Float, _ rhs: Float) { + lhs = lhs * rhs + } +} + +InoutParameterAutoDiffTests.test("ControlFlow") { + func sum(_ array: [Float]) -> Float { + var result: Float = 0 + for i in withoutDerivative(at: array.indices) { + result += array[i] + } + return result + } + expectEqual([1, 1, 1], gradient(at: [1, 2, 3], in: sum)) + + func product(_ array: [Float]) -> Float { + var result: Float = 1 + for i in withoutDerivative(at: array.indices) { + result *= array[i] + } + return result + } + expectEqual([20, 15, 12], gradient(at: [3, 4, 5], in: product)) + + func productCustom(_ array: [Float]) -> Float { + var result: Float = 1 + for i in withoutDerivative(at: array.indices) { + Float.multiplyAssign(&result, array[i]) + } + return result + } + expectEqual([20, 15, 12], gradient(at: [3, 4, 5], in: productCustom)) +} + +InoutParameterAutoDiffTests.test("SetAccessor") { + struct S: Differentiable { + var x: Float + + var computed: Float { + get { x } + set { x = newValue } + } + } + + // `squared` implemented using a `set` accessor. + func squared(_ x: Float) -> Float { + var s = S(x: 1) + s.x *= x + s.computed *= x + return s.x + } + expectEqual(6, gradient(at: 3, in: squared)) + expectEqual(8, gradient(at: 4, in: squared)) +} + +// Test differentiation wrt `inout` parameters that have a class type. +InoutParameterAutoDiffTests.test("InoutClassParameter") { + class Class: Differentiable { + @differentiable + var x: Float + + init(_ x: Float) { + self.x = x + } + } + + do { + func squaredViaMutation(_ c: inout Class) { + c = Class(c.x * c.x) + } + func squared(_ x: Float) -> Float { + var c = Class(x) + squaredViaMutation(&c) + return c.x + } + expectEqual((100, 20), valueWithGradient(at: 10, in: squared)) + expectEqual(200, pullback(at: 10, in: squared)(10)) + } + + do { + func squaredViaModifyAccessor(_ c: inout Class) { + // The line below calls `Class.x.modify`. + c.x *= c.x + } + func squared(_ x: Float) -> Float { + var c = Class(x) + squaredViaModifyAccessor(&c) + return c.x + } + // FIXME(TF-1080): Fix incorrect class property `modify` accessor derivative values. + // expectEqual((100, 20), valueWithGradient(at: 10, in: squared)) + // expectEqual(200, pullback(at: 10, in: squared)(10)) + expectEqual((100, 1), valueWithGradient(at: 10, in: squared)) + expectEqual(10, pullback(at: 10, in: squared)(10)) + } +} + // SR-13305: Test function with non-wrt `inout` parameter, which should be // treated as a differentiability result. From cc19330c75e18c01be618a4c6b5e6eb66c56fb93 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 19 Aug 2020 17:59:59 -0700 Subject: [PATCH 252/663] Codesign the Error binary before executing --- test/stdlib/Error.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stdlib/Error.swift b/test/stdlib/Error.swift index e235d6d296b98..69602edd2d8ad 100644 --- a/test/stdlib/Error.swift +++ b/test/stdlib/Error.swift @@ -1,11 +1,11 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -o %t/Error -DPTR_SIZE_%target-ptrsize -module-name main %/s +// RUN: %target-codesign %t/Error // RUN: %target-run %t/Error // REQUIRES: executable_test import StdlibUnittest - var ErrorTests = TestSuite("Error") var NoisyErrorLifeCount = 0 From b8976a3ec5c10d4b50e1a007f743bc48cc34fae1 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 19 Aug 2020 17:53:58 -0700 Subject: [PATCH 253/663] [SIL] Add flag to SILFunctionType::Profile for async. Previously, the flag was omitted, causing function types which were otherwise the same to have the same id, leading to caching woes. Here, the issue is fixed by adding the boolean flag to the id, ensuring that types which differ only in that flag are still understood to be different. --- include/swift/AST/Types.h | 4 ++-- lib/AST/ASTContext.cpp | 6 ++++-- test/SIL/Parser/async.sil | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index e3fbbd4e742c2..e55c8bf7be3d5 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -4577,14 +4577,14 @@ class SILFunctionType final void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInvocationGenericSignature(), - getExtInfo(), getCoroutineKind(), getCalleeConvention(), + getExtInfo(), isAsync(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), getWitnessMethodConformanceOrInvalid(), getPatternSubstitutions(), getInvocationSubstitutions()); } static void Profile(llvm::FoldingSetNodeID &ID, GenericSignature genericSig, ExtInfo info, - SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, + bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, ArrayRef yields, ArrayRef results, Optional errorResult, ProtocolConformanceRef conformance, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ef19cd4d46b31..e75c5185cc13b 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3245,6 +3245,7 @@ void SILFunctionType::Profile( llvm::FoldingSetNodeID &id, GenericSignature genericParams, ExtInfo info, + bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3258,6 +3259,7 @@ void SILFunctionType::Profile( auto infoKey = info.getFuncAttrKey(); id.AddInteger(infoKey.first); id.AddPointer(infoKey.second); + id.AddBoolean(isAsync); id.AddInteger(unsigned(coroutineKind)); id.AddInteger(unsigned(calleeConvention)); id.AddInteger(params.size()); @@ -3471,8 +3473,8 @@ CanSILFunctionType SILFunctionType::get( invocationSubs = invocationSubs.getCanonical(); llvm::FoldingSetNodeID id; - SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params, - yields, normalResults, errorResult, + SILFunctionType::Profile(id, genericSig, ext, isAsync, coroutineKind, callee, + params, yields, normalResults, errorResult, witnessMethodConformance, patternSubs, invocationSubs); diff --git a/test/SIL/Parser/async.sil b/test/SIL/Parser/async.sil index 374572412f494..32cfdebb32c0f 100644 --- a/test/SIL/Parser/async.sil +++ b/test/SIL/Parser/async.sil @@ -1,5 +1,21 @@ // RUN: %target-sil-opt -enable-sil-verify-all=true %s | %target-sil-opt -enable-sil-verify-all=true | %FileCheck %s +import Builtin + +// CHECK: sil @not_async_test : $@convention(thin) () -> () { +sil @not_async_test : $() -> () { +bb0: + %0 = tuple () + return %0 : $() +} + +// CHECK: sil @not_async_test2 : $@convention(thin) (Builtin.Int32) -> () { +sil @not_async_test2 : $(Builtin.Int32) -> () { +bb0(%int : $Builtin.Int32): + %0 = tuple () + return %0 : $() +} + // CHECK: sil @async_test : $@async sil @async_test : $@async () -> () { bb0: From ecd6d4ddec3db05b817ee40664e735153ac035b1 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 30 Jul 2020 12:13:20 -0400 Subject: [PATCH 254/663] Add a new ConcurrentReadableHashMap type. Switch the protocol conformance cache to use it. ConcurrentReadableHashMap is lock-free for readers, with writers using a lock to ensure mutual exclusion amongst each other. The intent is to eventually replace all uses ConcurrentMap with ConcurrentReadableHashMap. ConcurrentReadableHashMap provides for relatively quick lookups by using a hash table. Rearders perform an atomic increment/decrement in order to inform writers that there are active readers. The design attempts to minimize wasted memory by storing the actual elements out-of-line, and having the table store indices into a separate array of elements. The protocol conformance cache now uses ConcurrentReadableHashMap, which provides faster lookups and less memory use than the previous ConcurrentMap implementation. The previous implementation caches ProtocolConformanceDescriptors and extracts the WitnessTable after the cache lookup. The new implementation directly caches the WitnessTable, removing an extra step (potentially a quite slow one) from the fast path. The previous implementation used a generational scheme to detect when negative cache entries became obsolete due to new dynamic libraries being loaded, and update them in place. The new implementation just clears the entire cache when libraries are loaded, greatly simplifying the code and saving the memory needed to track the current generation in each negative cache entry. This means we need to re-cache all requested conformances after loading a dynamic library, but loading libraries at runtime is rare and slow anyway. rdar://problem/67268325 --- include/swift/Reflection/ReflectionContext.h | 51 ++- include/swift/Reflection/RuntimeInternals.h | 14 + include/swift/Runtime/Concurrent.h | 387 +++++++++++++++++- .../public/runtime/CompatibilityOverride.def | 7 - stdlib/public/runtime/ProtocolConformance.cpp | 306 ++++---------- .../Compatibility50/CompatibilityOverride.def | 226 ++++++++++ .../Compatibility50/CompatibilityOverride.h | 61 +++ .../toolchain/Compatibility50/Overrides.cpp | 4 +- .../Compatibility51/CompatibilityOverride.def | 226 ++++++++++ .../Compatibility51/CompatibilityOverride.h | 61 +++ .../toolchain/Compatibility51/Overrides.cpp | 4 +- .../Sources/swift-inspect/Inspector.swift | 24 +- unittests/runtime/CompatibilityOverride.cpp | 5 - unittests/runtime/Concurrent.cpp | 345 ++++++++++++++++ 14 files changed, 1483 insertions(+), 238 deletions(-) create mode 100644 stdlib/toolchain/Compatibility50/CompatibilityOverride.def create mode 100644 stdlib/toolchain/Compatibility50/CompatibilityOverride.h create mode 100644 stdlib/toolchain/Compatibility51/CompatibilityOverride.def create mode 100644 stdlib/toolchain/Compatibility51/CompatibilityOverride.h diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 0ff6c8b44436f..6fc3df0882f5f 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -879,7 +879,8 @@ class ReflectionContext std::function Call) { if (!NodePtr) return; - auto NodeBytes = getReader().readBytes(RemoteAddress(NodePtr), sizeof(Node)); + auto NodeBytes = getReader().readBytes(RemoteAddress(NodePtr), + sizeof(ConformanceNode)); auto NodeData = reinterpret_cast *>(NodeBytes.get()); if (!NodeData) @@ -889,6 +890,33 @@ class ReflectionContext iterateConformanceTree(NodeData->Right, Call); } + void IterateConformanceTable( + RemoteAddress ConformancesPtr, + std::function Call) { + auto MapBytes = getReader().readBytes(RemoteAddress(ConformancesPtr), + sizeof(ConcurrentHashMap)); + auto MapData = + reinterpret_cast *>(MapBytes.get()); + if (!MapData) + return; + + auto Count = MapData->ElementCount; + auto Size = Count * sizeof(ConformanceCacheEntry); + + auto ElementsBytes = + getReader().readBytes(RemoteAddress(MapData->Elements), Size); + auto ElementsData = + reinterpret_cast *>( + ElementsBytes.get()); + if (!ElementsData) + return; + + for (StoredSize i = 0; i < Count; i++) { + auto &Element = ElementsData[i]; + Call(Element.Type, Element.Proto); + } + } + /// Iterate the protocol conformance cache in the target process, calling Call /// with the type and protocol of each conformance. Returns None on success, /// and a string describing the error on failure. @@ -908,7 +936,26 @@ class ReflectionContext auto Root = getReader().readPointer(ConformancesAddr->getResolvedAddress(), sizeof(StoredPointer)); - iterateConformanceTree(Root->getResolvedAddress().getAddressData(), Call); + auto ReaderCount = Root->getResolvedAddress().getAddressData(); + + // ReaderCount will be the root pointer if the conformance cache is a + // ConcurrentMap. It's very unlikely that there would ever be more readers + // than the least valid pointer value, so compare with that to distinguish. + // TODO: once the old conformance cache is gone for good, remove that code. + uint64_t LeastValidPointerValue; + if (!getReader().queryDataLayout( + DataLayoutQueryType::DLQ_GetLeastValidPointerValue, nullptr, + &LeastValidPointerValue)) { + return std::string("unable to query least valid pointer value"); + } + + if (ReaderCount < LeastValidPointerValue) + IterateConformanceTable(ConformancesAddr->getResolvedAddress(), Call); + else { + // The old code has the root address at this location. + auto RootAddr = ReaderCount; + iterateConformanceTree(RootAddr, Call); + } return llvm::None; } diff --git a/include/swift/Reflection/RuntimeInternals.h b/include/swift/Reflection/RuntimeInternals.h index 11b6027242aaf..30ec8827c8515 100644 --- a/include/swift/Reflection/RuntimeInternals.h +++ b/include/swift/Reflection/RuntimeInternals.h @@ -46,6 +46,20 @@ template struct MetadataCacheNode { typename Runtime::StoredPointer Right; }; +template struct ConcurrentHashMap { + typename Runtime::StoredSize ReaderCount; + typename Runtime::StoredSize ElementCount; + typename Runtime::StoredPointer Elements; + typename Runtime::StoredPointer Indices; + // We'll ignore the remaining fields for now.... +}; + +template struct ConformanceCacheEntry { + typename Runtime::StoredPointer Type; + typename Runtime::StoredPointer Proto; + typename Runtime::StoredPointer Witness; +}; + } // end namespace reflection } // end namespace swift diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 7e4ed718b131b..17339f6503533 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -17,6 +17,7 @@ #include #include #include +#include "llvm/ADT/Hashing.h" #include "llvm/Support/Allocator.h" #include "Atomic.h" #include "Debug.h" @@ -26,6 +27,10 @@ #include #endif +#if defined(__APPLE__) && defined(__MACH__) +#include +#endif + namespace swift { /// This is a node in a concurrent linked list. @@ -488,8 +493,8 @@ template struct ConcurrentReadableArray { const ElemTy *end() { return Start + Count; } size_t count() { return Count; } }; - - // This type cannot be safely copied, moved, or deleted. + + // This type cannot be safely copied or moved. ConcurrentReadableArray(const ConcurrentReadableArray &) = delete; ConcurrentReadableArray(ConcurrentReadableArray &&) = delete; ConcurrentReadableArray &operator=(const ConcurrentReadableArray &) = delete; @@ -527,7 +532,7 @@ template struct ConcurrentReadableArray { if (ReaderCount.load(std::memory_order_acquire) == 0) deallocateFreeList(); } - + Snapshot snapshot() { incrementReaders(); auto *storage = Elements.load(SWIFT_MEMORY_ORDER_CONSUME); @@ -541,6 +546,382 @@ template struct ConcurrentReadableArray { } }; +using llvm::hash_value; + +/// A hash table that can be queried without taking any locks. Writes are still +/// locked and serialized, but only with respect to other locks. Writers can add +/// elements and clear the table, but they cannot remove individual elements. +/// Readers work by taking a snapshot of the table and then querying that +/// snapshot. +/// +/// The basic structure of the table consists of two arrays. Elements are stored +/// in a contiguous array, with new elements appended to the end. The second +/// array is the actual hash table, and it contains indices into the elements +/// array. This scheme cuts down on wasted space when the elements are larger +/// than a few bytes: instead of wasting `(1 - loadFactor) * sizeof(element)` +/// bytes on unused space in the hash table, we only waste `(1 - loadFactor) * +/// sizeof(index)`. This scheme also avoids readers seeing partially constructed +/// elements. +/// +/// Reader/writer synchronization for new elements is handled by keeping an +/// element count which is only incremented when the element has been fully +/// constructed. A reader which sees an index beyond its view of the current +/// count will ignore it and treat that as if there was no entry. +/// +/// Reader/writer synchronization for resizing the arrays is handled by tracking +/// the current number of active readers. When resizing, the new array is +/// allocated, the data copied, and then the old array is placed in a free list. +/// The free list is only deallocated if there are no readers, otherwise freeing +/// is deferred. +/// +/// Reader/writer synchronization for clearing the table is a combination of the +/// above. By keeping the old arrays around until all readers are finished, we +/// ensure that readers which started before the clear see valid (pre-clear) +/// data. Readers which see any array as empty will produce no results, thus +/// providing valid post-clear data. +template struct ConcurrentReadableHashMap { + // We use memcpy and don't call destructors. Make sure the elements will put + // up with this. + static_assert(std::is_trivially_copyable::value, + "Elements must be trivially copyable."); + static_assert(std::is_trivially_destructible::value, + "Elements must not have destructors (they won't be called)."); + +private: + /// The type of the elements of the indices array. TODO: use one or two byte + /// indices for smaller tables to save more memory. + using Index = unsigned; + + /// The reciprocal of the load factor at which we expand the table. A value of + /// 4 means that we resize at 1/4 = 75% load factor. + static const size_t ResizeProportion = 4; + + /// Get the "good size" for a given allocation size. When available, this + /// rounds up to the next allocation quantum by calling `malloc_good_size`. + /// Otherwise, just return the passed-in size, which is always valid even if + /// not necessarily optimal. + size_t goodSize(size_t size) { +#if defined(__APPLE__) && defined(__MACH__) + return malloc_good_size(size); +#else + return size; +#endif + } + + /// A private class representing the storage of the indices. In order to + /// ensure that readers can get a consistent view of the indices with a single + /// atomic read, we store the size of the indices array inline, as the first + /// element in the array. + /// + /// We want the number of indices to be a power of two so that we can use a + /// bitwise AND to convert a hash code to an index. We want the entire array + /// to be a power of two in size to be friendly to the allocator, but the size + /// is stored inline. We work around this contradiction by considering the + /// first index to always be occupied with a value that never matches any key. + struct IndexStorage { + std::atomic Mask; + + static IndexStorage *allocate(size_t capacity) { + assert((capacity & (capacity - 1)) == 0 && + "Capacity must be a power of 2"); + auto *ptr = + reinterpret_cast(calloc(capacity, sizeof(Mask))); + if (!ptr) + swift::crash("Could not allocate memory."); + ptr->Mask.store(capacity - 1, std::memory_order_relaxed); + return ptr; + } + + std::atomic &at(size_t i) { return (&Mask)[i]; } + }; + + /// The number of readers currently active, equal to the number of snapshot + /// objects currently alive. + std::atomic ReaderCount; + + /// The number of elements in the elements array. + std::atomic ElementCount; + + /// The array of elements. + std::atomic Elements; + + /// The array of indices. + std::atomic Indices; + + /// The writer lock, which must be taken before any mutation of the table. + Mutex WriterLock; + + /// The maximum number of elements that the current elements array can hold. + size_t ElementCapacity; + + /// The list of element arrays to be freed once no readers are active. + std::vector ElementFreeList; + + /// The list of index arrays to be freed once no readers are active. + std::vector IndicesFreeList; + + void incrementReaders() { + ReaderCount.fetch_add(1, std::memory_order_acquire); + } + + void decrementReaders() { + ReaderCount.fetch_sub(1, std::memory_order_release); + } + + /// Free all the arrays in the free lists. + void deallocateFreeList() { + for (auto *storage : ElementFreeList) + free(storage); + ElementFreeList.clear(); + ElementFreeList.shrink_to_fit(); + + for (auto *indices : IndicesFreeList) + free(indices); + IndicesFreeList.clear(); + IndicesFreeList.shrink_to_fit(); + } + + /// Free all the arrays in the free lists if there are no active readers. If + /// there are active readers, do nothing. + void deallocateFreeListIfSafe() { + if (ReaderCount.load(std::memory_order_relaxed) == 0) + deallocateFreeList(); + } + + /// Grow the elements array, adding the old array to the free list and + /// returning the new array with all existing elements copied into it. + ElemTy *resize(ElemTy *elements, size_t elementCount) { + // Grow capacity by 25%, making sure we grow by at least 1. + size_t newCapacity = + std::max(elementCount + (elementCount >> 2), elementCount + 1); + size_t newSize = newCapacity * sizeof(ElemTy); + + newSize = goodSize(newSize); + newCapacity = newSize / sizeof(ElemTy); + + ElemTy *newElements = static_cast(malloc(newSize)); + if (elements) { + memcpy(newElements, elements, elementCount * sizeof(ElemTy)); + ElementFreeList.push_back(elements); + } + + ElementCapacity = newCapacity; + Elements.store(newElements, std::memory_order_release); + return newElements; + } + + /// Grow the indices array, adding the old array to the free list and + /// returning the new array with all existing indices copied into it. This + /// operation performs a rehash, so that the indices are in the correct + /// location in the new array. + IndexStorage *resize(IndexStorage *indices, Index indicesMask, + ElemTy *elements) { + // Mask is size - 1. Double the size. Start with 4 (fits into 16-byte malloc + // bucket). + size_t newCount = indices ? 2 * (indicesMask + 1) : 4; + size_t newMask = newCount - 1; + + IndexStorage *newIndices = IndexStorage::allocate(newCount); + + for (size_t i = 1; i <= indicesMask; i++) { + Index index = indices->at(i).load(std::memory_order_relaxed); + if (index == 0) + continue; + + auto *element = &elements[index - 1]; + auto hash = hash_value(*element); + + size_t newI = hash & newMask; + while (newIndices->at(newI) != 0) + newI = (newI + 1) & newMask; + newIndices->at(newI).store(index, std::memory_order_relaxed); + } + + Indices.store(newIndices, std::memory_order_release); + + IndicesFreeList.push_back(indices); + + return newIndices; + } + + /// Search for the given key within the given indices and elements arrays. If + /// an entry already exists for that key, return a pointer to the element. If + /// no entry exists, return a pointer to the location in the indices array + /// where the index of the new element would be stored. + template + static std::pair *> + find(const KeyTy &key, IndexStorage *indices, size_t elementCount, + ElemTy *elements) { + if (!indices) + return {nullptr, nullptr}; + auto hash = hash_value(key); + auto indicesMask = indices->Mask.load(std::memory_order_relaxed); + + auto i = hash & indicesMask; + while (true) { + // Index 0 is used for the mask and is not actually an index. + if (i == 0) + i++; + + auto *indexPtr = &indices->at(i); + auto index = indexPtr->load(std::memory_order_acquire); + // Element indices are 1-based, 0 means no entry. + if (index == 0) + return {nullptr, indexPtr}; + if (index - 1 < elementCount) { + auto *candidate = &elements[index - 1]; + if (candidate->matchesKey(key)) + return {candidate, nullptr}; + } + + i = (i + 1) & indicesMask; + } + } + +public: + // This type cannot be safely copied or moved. + ConcurrentReadableHashMap(const ConcurrentReadableHashMap &) = delete; + ConcurrentReadableHashMap(ConcurrentReadableHashMap &&) = delete; + ConcurrentReadableHashMap & + operator=(const ConcurrentReadableHashMap &) = delete; + + ConcurrentReadableHashMap() + : ReaderCount(0), ElementCount(0), Elements(nullptr), Indices(nullptr), + ElementCapacity(0) {} + + ~ConcurrentReadableHashMap() { + assert(ReaderCount.load(std::memory_order_acquire) == 0 && + "deallocating ConcurrentReadableHashMap with outstanding snapshots"); + deallocateFreeList(); + } + + /// Readers take a snapshot of the hash map, then work with the snapshot. + class Snapshot { + ConcurrentReadableHashMap *Map; + IndexStorage *Indices; + ElemTy *Elements; + size_t ElementCount; + + public: + Snapshot(ConcurrentReadableHashMap *map, IndexStorage *indices, + ElemTy *elements, size_t elementCount) + : Map(map), Indices(indices), Elements(elements), + ElementCount(elementCount) {} + + Snapshot(const Snapshot &other) + : Map(other.Map), Indices(other.Indices), Elements(other.Elements), + ElementCount(other.ElementCount) { + Map->incrementReaders(); + } + + ~Snapshot() { Map->decrementReaders(); } + + /// Search for an element matching the given key. Returns a pointer to the + /// found element, or nullptr if no matching element exists. + template const ElemTy *find(const KeyTy &key) { + if (!Indices || !ElementCount || !Elements) + return nullptr; + return ConcurrentReadableHashMap::find(key, Indices, ElementCount, + Elements) + .first; + } + }; + + /// Take a snapshot of the current state of the hash map. + Snapshot snapshot() { + incrementReaders(); + auto *indices = Indices.load(SWIFT_MEMORY_ORDER_CONSUME); + auto elementCount = ElementCount.load(std::memory_order_acquire); + auto *elements = Elements.load(std::memory_order_acquire); + + return Snapshot(this, indices, elements, elementCount); + } + + /// Get an element by key, or insert a new element for that key if one is not + /// already present. Invoke `call` with the pointer to the element. BEWARE: + /// `call` is invoked with the internal writer lock held, keep work to a + /// minimum. + /// + /// `call` is passed the following parameters: + /// - `element`: the pointer to the element corresponding to `key` + /// - `created`: true if the element is newly created, false if it already + /// exists + /// `call` returns a `bool`. When `created` is `true`, the return values mean: + /// - `true` the new entry is to be kept + /// - `false` indicates that the new entry is discarded + /// If the new entry is kept, then the new element MUST be initialized, and + /// have a hash value that matches the hash value of `key`. + /// + /// The return value is ignored when `created` is `false`. + template + void getOrInsert(KeyTy key, const Call &call) { + ScopedLock guard(WriterLock); + + auto *indices = Indices.load(std::memory_order_relaxed); + if (!indices) + indices = resize(indices, 0, nullptr); + + auto indicesMask = indices->Mask.load(std::memory_order_relaxed); + auto elementCount = ElementCount.load(std::memory_order_relaxed); + auto *elements = Elements.load(std::memory_order_relaxed); + + auto found = find(key, indices, elementCount, elements); + if (found.first) { + call(found.first, false); + deallocateFreeListIfSafe(); + return; + } + + // The actual capacity is indicesMask + 1. The number of slots in use is + // elementCount + 1, since the mask also takes a slot. + auto emptyCount = (indicesMask + 1) - (elementCount + 1); + auto proportion = (indicesMask + 1) / emptyCount; + if (proportion >= ResizeProportion) { + indices = resize(indices, indicesMask, elements); + found = find(key, indices, elementCount, elements); + assert(!found.first && "Shouldn't suddenly find the key after rehashing"); + } + + if (elementCount >= ElementCapacity) { + elements = resize(elements, elementCount); + } + auto *element = &elements[elementCount]; + + // Order matters: fill out the element, then update the count, + // then update the index. + bool keep = call(element, true); + if (keep) { + assert(hash_value(key) == hash_value(*element) && + "Element must have the same hash code as its key."); + ElementCount.store(elementCount + 1, std::memory_order_release); + found.second->store(elementCount + 1, std::memory_order_release); + } + + deallocateFreeListIfSafe(); + } + + /// Clear the hash table, freeing (when safe) all memory currently used for + /// indices and elements. + void clear() { + ScopedLock guard(WriterLock); + + auto *indices = Indices.load(std::memory_order_relaxed); + auto *elements = Elements.load(std::memory_order_relaxed); + + // Order doesn't matter here, snapshots will gracefully handle any field + // being NULL/0 while the others are not. + Indices.store(nullptr, std::memory_order_relaxed); + ElementCount.store(0, std::memory_order_relaxed); + Elements.store(nullptr, std::memory_order_relaxed); + ElementCapacity = 0; + + IndicesFreeList.push_back(indices); + ElementFreeList.push_back(elements); + + deallocateFreeListIfSafe(); + } +}; + } // end namespace swift #endif // SWIFT_RUNTIME_CONCURRENTUTILS_H diff --git a/stdlib/public/runtime/CompatibilityOverride.def b/stdlib/public/runtime/CompatibilityOverride.def index 06ee84685dc35..92e32430251cd 100644 --- a/stdlib/public/runtime/CompatibilityOverride.def +++ b/stdlib/public/runtime/CompatibilityOverride.def @@ -134,13 +134,6 @@ OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocol, const WitnessTable *, , , swift const ProtocolDescriptor *protocol), (type, protocol)) -OVERRIDE_PROTOCOLCONFORMANCE(conformsToSwiftProtocol, - const ProtocolConformanceDescriptor *, , , swift::, - (const Metadata * const type, - const ProtocolDescriptor *protocol, - StringRef moduleName), - (type, protocol, moduleName)) - OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, (const void *pattern, const void *arguments), (pattern, arguments)) diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index 1a80b2e08e039..e373d2a50848e 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -198,31 +198,27 @@ namespace { : Type(type), Proto(proto) { assert(type); } + + friend llvm::hash_code hash_value(const ConformanceCacheKey &key) { + return llvm::hash_combine(key.Type, key.Proto); + } }; struct ConformanceCacheEntry { private: - const Metadata *Type; - const ProtocolDescriptor *Proto; - std::atomic Description; - std::atomic FailureGeneration; + ConformanceCacheKey Key; + const WitnessTable *Witness; public: - ConformanceCacheEntry(ConformanceCacheKey key, - const ProtocolConformanceDescriptor *description, - size_t failureGeneration) - : Type(key.Type), Proto(key.Proto), Description(description), - FailureGeneration(failureGeneration) { + ConformanceCacheEntry(ConformanceCacheKey key, const WitnessTable *witness) + : Key(key), Witness(witness) {} + + bool matchesKey(const ConformanceCacheKey &key) const { + return Key.Type == key.Type && Key.Proto == key.Proto; } - int compareWithKey(const ConformanceCacheKey &key) const { - if (key.Type != Type) { - return (uintptr_t(key.Type) < uintptr_t(Type) ? -1 : 1); - } else if (key.Proto != Proto) { - return (uintptr_t(key.Proto) < uintptr_t(Proto) ? -1 : 1); - } else { - return 0; - } + friend llvm::hash_code hash_value(const ConformanceCacheEntry &entry) { + return hash_value(entry.Key); } template @@ -230,69 +226,54 @@ namespace { return 0; } - bool isSuccessful() const { - return Description.load(std::memory_order_relaxed) != nullptr; - } - - void makeSuccessful(const ProtocolConformanceDescriptor *description) { - Description.store(description, std::memory_order_release); - } - - void updateFailureGeneration(size_t failureGeneration) { - assert(!isSuccessful()); - FailureGeneration.store(failureGeneration, std::memory_order_relaxed); - } - - /// Get the cached conformance descriptor, if successful. - const ProtocolConformanceDescriptor *getDescription() const { - assert(isSuccessful()); - return Description.load(std::memory_order_acquire); - } - - /// Get the generation in which this lookup failed. - size_t getFailureGeneration() const { - assert(!isSuccessful()); - return FailureGeneration.load(std::memory_order_relaxed); + /// Get the cached witness table, or null if we cached failure. + const WitnessTable *getWitnessTable() const { + return Witness; } }; } // end anonymous namespace // Conformance Cache. struct ConformanceState { - ConcurrentMap Cache; + ConcurrentReadableHashMap Cache; ConcurrentReadableArray SectionsToScan; ConformanceState() { initializeProtocolConformanceLookup(); } - void cacheSuccess(const Metadata *type, const ProtocolDescriptor *proto, - const ProtocolConformanceDescriptor *description) { - auto result = Cache.getOrInsert(ConformanceCacheKey(type, proto), - description, 0); - - // If the entry was already present, we may need to update it. - if (!result.second) { - result.first->makeSuccessful(description); - } - } - - void cacheFailure(const Metadata *type, const ProtocolDescriptor *proto, - size_t failureGeneration) { - auto result = - Cache.getOrInsert(ConformanceCacheKey(type, proto), - (const ProtocolConformanceDescriptor *) nullptr, - failureGeneration); - - // If the entry was already present, we may need to update it. - if (!result.second) { - result.first->updateFailureGeneration(failureGeneration); - } - } - - ConformanceCacheEntry *findCached(const Metadata *type, - const ProtocolDescriptor *proto) { - return Cache.find(ConformanceCacheKey(type, proto)); + void cacheResult(const Metadata *type, const ProtocolDescriptor *proto, + const WitnessTable *witness, size_t sectionsCount) { + Cache.getOrInsert(ConformanceCacheKey(type, proto), + [&](ConformanceCacheEntry *entry, bool created) { + // Create the entry if needed. If it already exists, + // we're done. + if (!created) + return false; + + // Check the current sections count against what was + // passed in. If a section count was passed in and they + // don't match, then this is not an authoritative entry + // and it may have been obsoleted, because the new + // sections could contain a conformance in a more + // specific type. + // + // If they DO match, then we can safely add. Another + // thread might be adding new sections at this point, + // but we will not race with them. That other thread + // will add the new sections, then clear the cache. When + // it clears the cache, it will block waiting for this + // code to complete and relinquish Cache's writer lock. + // If we cache a stale entry, it will be immediately + // cleared. + if (sectionsCount > 0 && + SectionsToScan.snapshot().count() != sectionsCount) + return false; // abandon the new entry + + new (entry) ConformanceCacheEntry( + ConformanceCacheKey(type, proto), witness); + return true; // keep the new entry + }); } #ifndef NDEBUG @@ -323,6 +304,10 @@ _registerProtocolConformances(ConformanceState &C, const ProtocolConformanceRecord *begin, const ProtocolConformanceRecord *end) { C.SectionsToScan.push_back(ConformanceSection{begin, end}); + + // Blow away the conformances cache to get rid of any negative entries that + // may now be obsolete. + C.Cache.clear(); } void swift::addImageProtocolConformanceBlockCallbackUnsafe( @@ -357,98 +342,29 @@ swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin _registerProtocolConformances(C, begin, end); } - -struct ConformanceCacheResult { - // true if description is an authoritative result as-is. - // false if more searching is required (for example, because a cached - // failure was returned in failureEntry but it is out-of-date. - bool isAuthoritative; - - // The matching conformance descriptor, or null if no cached conformance - // was found. - const ProtocolConformanceDescriptor *description; - - // If the search fails, this may be the negative cache entry for the - // queried type itself. This entry may be null or out-of-date. - ConformanceCacheEntry *failureEntry; - - static ConformanceCacheResult - cachedSuccess(const ProtocolConformanceDescriptor *description) { - return ConformanceCacheResult { true, description, nullptr }; - } - - static ConformanceCacheResult - cachedFailure(ConformanceCacheEntry *entry, bool auth) { - return ConformanceCacheResult { auth, nullptr, entry }; - } - - static ConformanceCacheResult - cacheMiss() { - return ConformanceCacheResult { false, nullptr, nullptr }; - } -}; - /// Search for a conformance descriptor in the ConformanceCache. -static -ConformanceCacheResult +/// First element of the return value is `true` if the result is authoritative +/// i.e. the result is for the type itself and not a superclass. If `false` +/// then we cached a conformance on a superclass, but that may be overridden. +/// A return value of `{ false, nullptr }` indicates nothing was cached. +static std::pair searchInConformanceCache(const Metadata *type, const ProtocolDescriptor *protocol) { auto &C = Conformances.get(); auto origType = type; - ConformanceCacheEntry *failureEntry = nullptr; - -recur: - { - // Try the specific type first. - if (auto *Value = C.findCached(type, protocol)) { - if (Value->isSuccessful()) { - // Found a conformance on the type or some superclass. Return it. - return ConformanceCacheResult::cachedSuccess(Value->getDescription()); - } - - // Found a negative cache entry. - - bool isAuthoritative; - if (type == origType) { - // This negative cache entry is for the original query type. - // Remember it so it can be returned later. - failureEntry = Value; - // An up-to-date entry for the original type is authoritative. - isAuthoritative = true; - } else { - // An up-to-date cached failure for a superclass of the type is not - // authoritative: there may be a still-undiscovered conformance - // for the original query type. - isAuthoritative = false; - } + auto snapshot = C.Cache.snapshot(); - // Check if the negative cache entry is up-to-date. - if (Value->getFailureGeneration() == C.SectionsToScan.snapshot().count()) { - // Negative cache entry is up-to-date. Return failure along with - // the original query type's own cache entry, if we found one. - // (That entry may be out of date but the caller still has use for it.) - return ConformanceCacheResult::cachedFailure(failureEntry, - isAuthoritative); - } - - // Negative cache entry is out-of-date. - // Continue searching for a better result. + while (type) { + if (auto *Value = snapshot.find(ConformanceCacheKey(type, protocol))) { + return {type == origType, Value->getWitnessTable()}; } - } - // If there is a superclass, look there. - if (auto superclass = _swift_class_getSuperclass(type)) { - type = superclass; - goto recur; + // If there is a superclass, look there. + type = _swift_class_getSuperclass(type); } - // We did not find an up-to-date cache entry. - // If we found an out-of-date entry for the original query type then - // return it (non-authoritatively). Otherwise return a cache miss. - if (failureEntry) - return ConformanceCacheResult::cachedFailure(failureEntry, false); - else - return ConformanceCacheResult::cacheMiss(); + // We did not find a cache entry. + return {false, nullptr}; } namespace { @@ -477,14 +393,6 @@ namespace { } } - /// Retrieve the conforming type as metadata, or NULL if the candidate's - /// conforming type is described in another way (e.g., a nominal type - /// descriptor). - const Metadata *getConformingTypeAsMetadata() const { - return candidateIsMetadata ? static_cast(candidate) - : nullptr; - } - const ContextDescriptor * getContextDescriptor(const Metadata *conformingType) const { const auto *description = conformingType->getTypeContextDescriptor(); @@ -544,40 +452,21 @@ namespace { }; } -static const ProtocolConformanceDescriptor * -swift_conformsToSwiftProtocolImpl(const Metadata * const type, - const ProtocolDescriptor *protocol, - StringRef module) { +static const WitnessTable * +swift_conformsToProtocolImpl(const Metadata *const type, + const ProtocolDescriptor *protocol) { auto &C = Conformances.get(); - // See if we have a cached conformance. The ConcurrentMap data structure - // allows us to insert and search the map concurrently without locking. - auto FoundConformance = searchInConformanceCache(type, protocol); - // If the result (positive or negative) is authoritative, return it. - if (FoundConformance.isAuthoritative) - return FoundConformance.description; + // See if we have an authoritative cached conformance. The + // ConcurrentReadableHashMap data structure allows us to search the map + // concurrently without locking. + auto found = searchInConformanceCache(type, protocol); + if (found.first) + return found.second; - auto failureEntry = FoundConformance.failureEntry; - - // Prepare to scan conformance records. + // Scan conformance records. auto snapshot = C.SectionsToScan.snapshot(); - - // Scan only sections that were not scanned yet. - // If we found an out-of-date negative cache entry, - // we need not to re-scan the sections that it covers. - auto startIndex = failureEntry ? failureEntry->getFailureGeneration() : 0; - auto endIndex = snapshot.count(); - - // If there are no unscanned sections outstanding - // then we can cache failure and give up now. - if (startIndex == endIndex) { - C.cacheFailure(type, protocol, snapshot.count()); - return nullptr; - } - - // Really scan conformance records. - for (size_t i = startIndex; i < endIndex; ++i) { - auto §ion = snapshot.Start[i]; + for (auto §ion : snapshot) { // Eagerly pull records for nondependent witnesses into our cache. for (const auto &record : section) { auto &descriptor = *record.get(); @@ -586,40 +475,25 @@ swift_conformsToSwiftProtocolImpl(const Metadata * const type, if (descriptor.getProtocol() != protocol) continue; - // If there's a matching type, record the positive result. + // If there's a matching type, record the positive result and return it. + // The matching type is exact, so they can't go stale, and we should + // always cache them. ConformanceCandidate candidate(descriptor); - if (candidate.getMatchingType(type)) { - const Metadata *matchingType = candidate.getConformingTypeAsMetadata(); - if (!matchingType) - matchingType = type; - - C.cacheSuccess(matchingType, protocol, &descriptor); + if (auto *matchingType = candidate.getMatchingType(type)) { + auto witness = descriptor.getWitnessTable(matchingType); + C.cacheResult(matchingType, protocol, witness, /*always cache*/ 0); } } } - - // Conformance scan is complete. - - // Search the cache once more, and this time update the cache if necessary. - FoundConformance = searchInConformanceCache(type, protocol); - if (FoundConformance.isAuthoritative) { - return FoundConformance.description; - } else { - C.cacheFailure(type, protocol, snapshot.count()); - return nullptr; - } -} -static const WitnessTable * -swift_conformsToProtocolImpl(const Metadata * const type, - const ProtocolDescriptor *protocol) { - auto description = - swift_conformsToSwiftProtocol(type, protocol, StringRef()); - if (!description) - return nullptr; + // Try the search again to look for the most specific cached conformance. + found = searchInConformanceCache(type, protocol); + + // If it's not authoritative, then add an authoritative entry for this type. + if (!found.first) + C.cacheResult(type, protocol, found.second, snapshot.count()); - return description->getWitnessTable( - findConformingSuperclass(type, description)); + return found.second; } const ContextDescriptor * diff --git a/stdlib/toolchain/Compatibility50/CompatibilityOverride.def b/stdlib/toolchain/Compatibility50/CompatibilityOverride.def new file mode 100644 index 0000000000000..06ee84685dc35 --- /dev/null +++ b/stdlib/toolchain/Compatibility50/CompatibilityOverride.def @@ -0,0 +1,226 @@ +//===--- CompatibilityOverrides.def - Compatibility Overrides Database -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines x-macros used for metaprogramming with the set of +// compatibility override functions. +// +//===----------------------------------------------------------------------===// + +/// #define OVERRIDE(name, ret, attrs, namespace, typedArgs, namedArgs) +/// Provides information about an overridable function. +/// - name is the name of the function, without any leading swift_ or +/// namespace. +/// - ret is the return type of the function. +/// - attrs is the attributes, if any, applied to the function definition. +/// - namespace is the namespace, if any, the function is in, including a +/// trailing :: +/// - typedArgs is the argument list, including types, surrounded by +/// parentheses +/// - namedArgs is the list of argument names, with no types, surrounded by +/// parentheses +/// +/// The entries are organized by group. A user may define OVERRIDE to get all +/// entries, or define one or more of OVERRIDE_METADATALOOKUP, OVERRIDE_CASTING, +/// OVERRIDE_OBJC, OVERRIDE_FOREIGN, OVERRIDE_PROTOCOLCONFORMANCE, +/// and OVERRIDE_KEYPATH to get only those entries. + +// NOTE: this file is used to build the definition of OverrideSection in +// CompatibilityOverride.cpp, which is part of the ABI. Do not move or remove entries +// in this file after ABI stability. Additional entries can be added to the end. + +#ifdef OVERRIDE +# define OVERRIDE_METADATALOOKUP OVERRIDE +# define OVERRIDE_CASTING OVERRIDE +# define OVERRIDE_OBJC OVERRIDE +# define OVERRIDE_FOREIGN OVERRIDE +# define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE +# define OVERRIDE_KEYPATH OVERRIDE +# define OVERRIDE_WITNESSTABLE OVERRIDE +#else +# ifndef OVERRIDE_METADATALOOKUP +# define OVERRIDE_METADATALOOKUP(...) +# endif +# ifndef OVERRIDE_CASTING +# define OVERRIDE_CASTING(...) +# endif +# ifndef OVERRIDE_OBJC +# define OVERRIDE_OBJC(...) +# endif +# ifndef OVERRIDE_FOREIGN +# define OVERRIDE_FOREIGN(...) +# endif +# ifndef OVERRIDE_PROTOCOLCONFORMANCE +# define OVERRIDE_PROTOCOLCONFORMANCE(...) +# endif +# ifndef OVERRIDE_KEYPATH +# define OVERRIDE_KEYPATH(...) +# endif +# ifndef OVERRIDE_WITNESSTABLE +# define OVERRIDE_WITNESSTABLE(...) +# endif +#endif + +OVERRIDE_CASTING(dynamicCast, bool, , , swift::, + (OpaqueValue *dest, OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags), + (dest, src, srcType, targetType, flags)) + + +OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + + +OVERRIDE_CASTING(dynamicCastUnknownClass, const void *, , , swift::, + (const void *object, const Metadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastUnknownClassUnconditional, const void *, , , swift::, + (const void *object, const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + +OVERRIDE_CASTING(dynamicCastMetatype, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_CASTING(dynamicCastMetatypeUnconditional, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatypeUnconditional, + const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocol, const WitnessTable *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol), + (type, protocol)) + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToSwiftProtocol, + const ProtocolConformanceDescriptor *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol, + StringRef moduleName), + (type, protocol, moduleName)) + +OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, + (const void *pattern, const void *arguments), + (pattern, arguments)) + +OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + Demangler &demangler, + Demangle::NodePointer node, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, demangler, node, arguments, substGenericParam, substWitnessTable)) +OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + StringRef typeName, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, typeName, arguments, substGenericParam, substWitnessTable)) + +OVERRIDE_WITNESSTABLE(getAssociatedTypeWitnessSlow, MetadataResponse, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (MetadataRequest request, WitnessTable *wtable, + const Metadata *conformingType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocType), + (request, wtable, conformingType, reqBase, assocType)) + +OVERRIDE_WITNESSTABLE(getAssociatedConformanceWitnessSlow, const WitnessTable *, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (WitnessTable *wtable, const Metadata *conformingType, + const Metadata *assocType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocConformance), + (wtable, conformingType, assocType, reqBase, + assocConformance)) +#if SWIFT_OBJC_INTEROP + +OVERRIDE_OBJC(dynamicCastObjCClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +OVERRIDE_OBJC(dynamicCastObjCClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassMetatypeUnconditional, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClass, const void *, , , swift::, + (const void *object, + const ForeignClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift::, + (const void *object, const ForeignClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +#endif + +#undef OVERRIDE +#undef OVERRIDE_METADATALOOKUP +#undef OVERRIDE_CASTING +#undef OVERRIDE_OBJC +#undef OVERRIDE_FOREIGN +#undef OVERRIDE_PROTOCOLCONFORMANCE +#undef OVERRIDE_KEYPATH +#undef OVERRIDE_WITNESSTABLE diff --git a/stdlib/toolchain/Compatibility50/CompatibilityOverride.h b/stdlib/toolchain/Compatibility50/CompatibilityOverride.h new file mode 100644 index 0000000000000..e726e41958f50 --- /dev/null +++ b/stdlib/toolchain/Compatibility50/CompatibilityOverride.h @@ -0,0 +1,61 @@ +//===--- CompatibiltyOverride.h - Back-deploying compatibility fixes --*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Support back-deploying compatibility fixes for newer apps running on older runtimes. +// +//===----------------------------------------------------------------------===// + +#ifndef COMPATIBILITY_OVERRIDE_H +#define COMPATIBILITY_OVERRIDE_H + +#include "../../public/runtime/Private.h" +#include "swift/Runtime/Metadata.h" +#include "swift/Runtime/Once.h" +#include + +namespace swift { + +#define COMPATIBILITY_UNPAREN(...) __VA_ARGS__ + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Original_ ## name) typedArgs; +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Override_ ## name)(COMPATIBILITY_UNPAREN typedArgs, \ + Original_ ## name originalImpl); +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + Override_ ## name getOverride_ ## name(); +#include "CompatibilityOverride.def" + + +/// Used to define an override point. The override point #defines the appropriate +/// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes +/// the file to generate the override points. The original implementation of the +/// functionality must be available as swift_funcNameHereImpl. +#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + attrs ccAttrs ret namespace swift_ ## name typedArgs { \ + static Override_ ## name Override; \ + static swift_once_t Predicate; \ + swift_once(&Predicate, [](void *) { \ + Override = getOverride_ ## name(); \ + }, nullptr); \ + if (Override != nullptr) \ + return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ + return swift_ ## name ## Impl namedArgs; \ + } + +} /* end namespace swift */ + +#endif /* COMPATIBILITY_OVERRIDE_H */ diff --git a/stdlib/toolchain/Compatibility50/Overrides.cpp b/stdlib/toolchain/Compatibility50/Overrides.cpp index bc6f88625256b..fcaccf3b0fb4d 100644 --- a/stdlib/toolchain/Compatibility50/Overrides.cpp +++ b/stdlib/toolchain/Compatibility50/Overrides.cpp @@ -16,7 +16,7 @@ #include "Overrides.h" #include "../Compatibility51/Overrides.h" -#include "../../public/runtime/CompatibilityOverride.h" +#include "CompatibilityOverride.h" #include #include @@ -28,7 +28,7 @@ struct OverrideSection { uintptr_t version; #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ Override_ ## name name; -#include "../../public/runtime/CompatibilityOverride.def" +#include "CompatibilityOverride.def" }; OverrideSection Swift50Overrides diff --git a/stdlib/toolchain/Compatibility51/CompatibilityOverride.def b/stdlib/toolchain/Compatibility51/CompatibilityOverride.def new file mode 100644 index 0000000000000..06ee84685dc35 --- /dev/null +++ b/stdlib/toolchain/Compatibility51/CompatibilityOverride.def @@ -0,0 +1,226 @@ +//===--- CompatibilityOverrides.def - Compatibility Overrides Database -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines x-macros used for metaprogramming with the set of +// compatibility override functions. +// +//===----------------------------------------------------------------------===// + +/// #define OVERRIDE(name, ret, attrs, namespace, typedArgs, namedArgs) +/// Provides information about an overridable function. +/// - name is the name of the function, without any leading swift_ or +/// namespace. +/// - ret is the return type of the function. +/// - attrs is the attributes, if any, applied to the function definition. +/// - namespace is the namespace, if any, the function is in, including a +/// trailing :: +/// - typedArgs is the argument list, including types, surrounded by +/// parentheses +/// - namedArgs is the list of argument names, with no types, surrounded by +/// parentheses +/// +/// The entries are organized by group. A user may define OVERRIDE to get all +/// entries, or define one or more of OVERRIDE_METADATALOOKUP, OVERRIDE_CASTING, +/// OVERRIDE_OBJC, OVERRIDE_FOREIGN, OVERRIDE_PROTOCOLCONFORMANCE, +/// and OVERRIDE_KEYPATH to get only those entries. + +// NOTE: this file is used to build the definition of OverrideSection in +// CompatibilityOverride.cpp, which is part of the ABI. Do not move or remove entries +// in this file after ABI stability. Additional entries can be added to the end. + +#ifdef OVERRIDE +# define OVERRIDE_METADATALOOKUP OVERRIDE +# define OVERRIDE_CASTING OVERRIDE +# define OVERRIDE_OBJC OVERRIDE +# define OVERRIDE_FOREIGN OVERRIDE +# define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE +# define OVERRIDE_KEYPATH OVERRIDE +# define OVERRIDE_WITNESSTABLE OVERRIDE +#else +# ifndef OVERRIDE_METADATALOOKUP +# define OVERRIDE_METADATALOOKUP(...) +# endif +# ifndef OVERRIDE_CASTING +# define OVERRIDE_CASTING(...) +# endif +# ifndef OVERRIDE_OBJC +# define OVERRIDE_OBJC(...) +# endif +# ifndef OVERRIDE_FOREIGN +# define OVERRIDE_FOREIGN(...) +# endif +# ifndef OVERRIDE_PROTOCOLCONFORMANCE +# define OVERRIDE_PROTOCOLCONFORMANCE(...) +# endif +# ifndef OVERRIDE_KEYPATH +# define OVERRIDE_KEYPATH(...) +# endif +# ifndef OVERRIDE_WITNESSTABLE +# define OVERRIDE_WITNESSTABLE(...) +# endif +#endif + +OVERRIDE_CASTING(dynamicCast, bool, , , swift::, + (OpaqueValue *dest, OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags), + (dest, src, srcType, targetType, flags)) + + +OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + + +OVERRIDE_CASTING(dynamicCastUnknownClass, const void *, , , swift::, + (const void *object, const Metadata *targetType), + (object, targetType)) + + +OVERRIDE_CASTING(dynamicCastUnknownClassUnconditional, const void *, , , swift::, + (const void *object, const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + + +OVERRIDE_CASTING(dynamicCastMetatype, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_CASTING(dynamicCastMetatypeUnconditional, const Metadata *, , , swift::, + (const Metadata *sourceType, + const Metadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassMetatypeUnconditional, + const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocol, const WitnessTable *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol), + (type, protocol)) + +OVERRIDE_PROTOCOLCONFORMANCE(conformsToSwiftProtocol, + const ProtocolConformanceDescriptor *, , , swift::, + (const Metadata * const type, + const ProtocolDescriptor *protocol, + StringRef moduleName), + (type, protocol, moduleName)) + +OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, + (const void *pattern, const void *arguments), + (pattern, arguments)) + +OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + Demangler &demangler, + Demangle::NodePointer node, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, demangler, node, arguments, substGenericParam, substWitnessTable)) +OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeInfo, , SWIFT_CC(swift), swift::, + (MetadataRequest request, + StringRef typeName, + const void * const *arguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable), + (request, typeName, arguments, substGenericParam, substWitnessTable)) + +OVERRIDE_WITNESSTABLE(getAssociatedTypeWitnessSlow, MetadataResponse, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (MetadataRequest request, WitnessTable *wtable, + const Metadata *conformingType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocType), + (request, wtable, conformingType, reqBase, assocType)) + +OVERRIDE_WITNESSTABLE(getAssociatedConformanceWitnessSlow, const WitnessTable *, + SWIFT_RUNTIME_STDLIB_INTERNAL, SWIFT_CC(swift), swift::, + (WitnessTable *wtable, const Metadata *conformingType, + const Metadata *assocType, + const ProtocolRequirement *reqBase, + const ProtocolRequirement *assocConformance), + (wtable, conformingType, assocType, reqBase, + assocConformance)) +#if SWIFT_OBJC_INTEROP + +OVERRIDE_OBJC(dynamicCastObjCClass, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassUnconditional, const void *, , , swift::, + (const void *object, + const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +OVERRIDE_OBJC(dynamicCastObjCClassMetatype, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, + const ClassMetadata *targetType), + (sourceType, targetType)) + + +OVERRIDE_OBJC(dynamicCastObjCClassMetatypeUnconditional, const ClassMetadata *, , , swift::, + (const ClassMetadata *sourceType, const ClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (sourceType, targetType, file, line, column)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClass, const void *, , , swift::, + (const void *object, + const ForeignClassMetadata *targetType), + (object, targetType)) + + +OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift::, + (const void *object, const ForeignClassMetadata *targetType, + const char *file, unsigned line, unsigned column), + (object, targetType, file, line, column)) + +#endif + +#undef OVERRIDE +#undef OVERRIDE_METADATALOOKUP +#undef OVERRIDE_CASTING +#undef OVERRIDE_OBJC +#undef OVERRIDE_FOREIGN +#undef OVERRIDE_PROTOCOLCONFORMANCE +#undef OVERRIDE_KEYPATH +#undef OVERRIDE_WITNESSTABLE diff --git a/stdlib/toolchain/Compatibility51/CompatibilityOverride.h b/stdlib/toolchain/Compatibility51/CompatibilityOverride.h new file mode 100644 index 0000000000000..e726e41958f50 --- /dev/null +++ b/stdlib/toolchain/Compatibility51/CompatibilityOverride.h @@ -0,0 +1,61 @@ +//===--- CompatibiltyOverride.h - Back-deploying compatibility fixes --*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Support back-deploying compatibility fixes for newer apps running on older runtimes. +// +//===----------------------------------------------------------------------===// + +#ifndef COMPATIBILITY_OVERRIDE_H +#define COMPATIBILITY_OVERRIDE_H + +#include "../../public/runtime/Private.h" +#include "swift/Runtime/Metadata.h" +#include "swift/Runtime/Once.h" +#include + +namespace swift { + +#define COMPATIBILITY_UNPAREN(...) __VA_ARGS__ + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Original_ ## name) typedArgs; +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + ccAttrs typedef ret (*Override_ ## name)(COMPATIBILITY_UNPAREN typedArgs, \ + Original_ ## name originalImpl); +#include "CompatibilityOverride.def" + +#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + Override_ ## name getOverride_ ## name(); +#include "CompatibilityOverride.def" + + +/// Used to define an override point. The override point #defines the appropriate +/// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes +/// the file to generate the override points. The original implementation of the +/// functionality must be available as swift_funcNameHereImpl. +#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + attrs ccAttrs ret namespace swift_ ## name typedArgs { \ + static Override_ ## name Override; \ + static swift_once_t Predicate; \ + swift_once(&Predicate, [](void *) { \ + Override = getOverride_ ## name(); \ + }, nullptr); \ + if (Override != nullptr) \ + return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ + return swift_ ## name ## Impl namedArgs; \ + } + +} /* end namespace swift */ + +#endif /* COMPATIBILITY_OVERRIDE_H */ diff --git a/stdlib/toolchain/Compatibility51/Overrides.cpp b/stdlib/toolchain/Compatibility51/Overrides.cpp index 5e1eb78f3ab37..f9a89ec39e115 100644 --- a/stdlib/toolchain/Compatibility51/Overrides.cpp +++ b/stdlib/toolchain/Compatibility51/Overrides.cpp @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -#include "../../public/runtime/CompatibilityOverride.h" +#include "CompatibilityOverride.h" #include "Overrides.h" #include @@ -27,7 +27,7 @@ struct OverrideSection { uintptr_t version; #define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ Override_ ## name name; -#include "../../public/runtime/CompatibilityOverride.def" +#include "CompatibilityOverride.def" }; OverrideSection Swift51Overrides diff --git a/tools/swift-inspect/Sources/swift-inspect/Inspector.swift b/tools/swift-inspect/Sources/swift-inspect/Inspector.swift index 80f3668f111b3..05b77192adf68 100644 --- a/tools/swift-inspect/Sources/swift-inspect/Inspector.swift +++ b/tools/swift-inspect/Sources/swift-inspect/Inspector.swift @@ -121,8 +121,10 @@ private func QueryDataLayoutFn(context: UnsafeMutableRawPointer?, type: DataLayoutQueryType, inBuffer: UnsafeMutableRawPointer?, outBuffer: UnsafeMutableRawPointer?) -> CInt { + let is64 = MemoryLayout.stride == 8 + switch type { - case DLQ_GetPointerSize: + case DLQ_GetPointerSize, DLQ_GetSizeSize: let size = UInt8(MemoryLayout.stride) outBuffer!.storeBytes(of: size, toByteOffset: 0, as: UInt8.self) return 1 @@ -130,6 +132,26 @@ private func QueryDataLayoutFn(context: UnsafeMutableRawPointer?, let mask = GetPtrauthMask() outBuffer!.storeBytes(of: mask, toByteOffset: 0, as: UInt.self) return 1 + case DLQ_GetObjCReservedLowBits: + var size: UInt8 = 0 +#if os(macOS) + // The low bit is reserved only on 64-bit macOS. + if is64 { + size = 1 + } +#endif + outBuffer!.storeBytes(of: size, toByteOffset: 0, as: UInt8.self) + return 1 + case DLQ_GetLeastValidPointerValue: + var value: UInt64 = 0x1000 +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) + // 64-bit Apple platforms reserve the low 4GB. + if is64 { + value = 0x100000000 + } +#endif + outBuffer!.storeBytes(of: value, toByteOffset: 0, as: UInt64.self) + return 1 default: return 0 } diff --git a/unittests/runtime/CompatibilityOverride.cpp b/unittests/runtime/CompatibilityOverride.cpp index 2dece35195619..80a9b086980b9 100644 --- a/unittests/runtime/CompatibilityOverride.cpp +++ b/unittests/runtime/CompatibilityOverride.cpp @@ -168,11 +168,6 @@ TEST_F(CompatibilityOverrideTest, test_swift_conformsToProtocol) { ASSERT_EQ(Result, nullptr); } -TEST_F(CompatibilityOverrideTest, test_swift_conformsToSwiftProtocol) { - auto Result = swift_conformsToSwiftProtocol(nullptr, nullptr, StringRef()); - ASSERT_EQ(Result, nullptr); -} - TEST_F(CompatibilityOverrideTest, test_swift_getTypeByMangledNode) { Demangler demangler; auto Result = swift_getTypeByMangledNode(MetadataState::Abstract, diff --git a/unittests/runtime/Concurrent.cpp b/unittests/runtime/Concurrent.cpp index 00f09675d6958..141b804f099d4 100644 --- a/unittests/runtime/Concurrent.cpp +++ b/unittests/runtime/Concurrent.cpp @@ -154,3 +154,348 @@ TEST(ConcurrentReadableArrayTest, MultiThreaded2) { ASSERT_EQ(array.snapshot().count(), (size_t)writerCount * insertCount); } + +struct SingleThreadedValue { + size_t key; + size_t x; + SingleThreadedValue(size_t key, size_t x) : key(key), x(x) {} + bool matchesKey(size_t key) { return this->key == key; } + friend llvm::hash_code hash_value(const SingleThreadedValue &value) { + return llvm::hash_value(value.key); + } +}; + +TEST(ConcurrentReadableHashMapTest, SingleThreaded) { + ConcurrentReadableHashMap map; + + auto permute = [](size_t value) { return value ^ 0x33333333U; }; + + auto add = [&](size_t limit) { + for (size_t i = 0; i < limit; i++) + map.getOrInsert(permute(i), + [&](SingleThreadedValue *value, bool created) { + if (created) + new (value) SingleThreadedValue(permute(i), i); + return true; + }); + }; + auto check = [&](size_t limit) { + auto snapshot = map.snapshot(); + ASSERT_EQ(snapshot.find((size_t)~0), nullptr); + for (size_t i = 0; i < limit; i++) { + auto *value = snapshot.find(permute(i)); + ASSERT_NE(value, nullptr); + ASSERT_EQ(permute(i), value->key); + ASSERT_EQ(i, value->x); + } + }; + + check(0); + add(1); + check(1); + add(16); + check(16); + add(100); + check(100); + add(1000); + check(1000); + add(1000000); + check(1000000); + + map.clear(); + check(0); + + add(1); + check(1); + map.clear(); + check(0); + + add(16); + check(16); + map.clear(); + check(0); + + add(100); + check(100); + map.clear(); + check(0); + + add(1000); + check(1000); + map.clear(); + check(0); + + add(1000000); + check(1000000); + map.clear(); + check(0); +} + +struct MultiThreadedKey { + int threadNumber; + int n; + friend llvm::hash_code hash_value(const MultiThreadedKey &value) { + return llvm::hash_combine(value.threadNumber, value.n); + } +}; + +struct MultiThreadedValue { + int threadNumber; + int n; + int x; + MultiThreadedValue(MultiThreadedKey key, int x) + : threadNumber(key.threadNumber), n(key.n), x(x) {} + bool matchesKey(const MultiThreadedKey &key) { + return threadNumber == key.threadNumber && n == key.n; + } + friend llvm::hash_code hash_value(const MultiThreadedValue &value) { + return llvm::hash_combine(value.threadNumber, value.n); + } +}; + +// Test simultaneous readers and writers. +TEST(ConcurrentReadableHashMapTest, MultiThreaded) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + // NOTE: The bizarre lambdas around the ASSERT_ statements works around the + // fact that these macros emit return statements, which conflict with our + // need to return true/false from these lambdas. Wrapping them in a lambda + // neutralizes the return. + + auto writer = [&](int threadNumber) { + // Insert half, then insert all, to test adding an existing key. + for (int i = 0; i < insertCount / 2; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + // Test discarding a new entry. + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, + [&](MultiThreadedValue *value, bool created) { + [&] { ASSERT_EQ(created, i >= insertCount / 2); }(); + return false; + }); + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + if (created) { + [&] { ASSERT_GE(i, insertCount / 2); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + } else { + [&] { ASSERT_LT(i, insertCount / 2); }(); + } + return true; + }); + }; + + auto reader = [&] { + bool done = false; + while (!done) { + done = true; + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // Read from the top down. We should see zero or more missing entries, + // and then the rest are present. Any hole is a bug. + int firstSeen = -1; + auto snapshot = map.snapshot(); + for (int i = insertCount - 1; i >= 0; i--) { + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + if (firstSeen == -1) + firstSeen = value->x; + ASSERT_EQ(value->x, i); + } else { + ASSERT_EQ(firstSeen, -1); + done = false; + } + } + } + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); +} + +// Test readers and writers while also constantly clearing the map. +TEST(ConcurrentReadableHashMapTest, MultiThreaded2) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + std::atomic writerDoneCount = {0}; + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + writerDoneCount.fetch_add(1, std::memory_order_relaxed); + }; + + auto reader = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // Read from the top down. We should see a single contiguous region of + // entries. Multiple regions indicates a bug. + int firstSeen = -1; + int lastSeen = -1; + auto snapshot = map.snapshot(); + for (int i = insertCount - 1; i >= 0; i--) { + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + if (firstSeen == -1) + firstSeen = value->x; + if (lastSeen != -1) + ASSERT_EQ(lastSeen, i + 1); + lastSeen = value->x; + ASSERT_EQ(value->x, i); + } + } + } + } + }; + + auto clear = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + map.clear(); + } + }; + + threadedExecute(writerCount + readerCount + 1, [&](int i) { + if (i < writerCount) + writer(i); + else if (i < writerCount + readerCount) + reader(); + else + clear(); + }); +} + +// Test readers and writers, with readers taking lots of snapshots. +TEST(ConcurrentReadableHashMapTest, MultiThreaded3) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + std::atomic writerDoneCount = {0}; + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + writerDoneCount.fetch_add(1, std::memory_order_relaxed); + }; + + auto reader = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // Read from the top down. When we're not clearing the map, we should + // see zero or more missing entries, and then the rest are present. Any + // hole is a bug. + int firstSeen = -1; + int lastSeen = -1; + for (int i = insertCount - 1; i >= 0; i--) { + auto snapshot = map.snapshot(); + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + if (firstSeen == -1) + firstSeen = value->x; + if (lastSeen != -1) + ASSERT_EQ(lastSeen, i + 1); + lastSeen = value->x; + ASSERT_EQ(value->x, i); + } + } + } + } + }; + + threadedExecute(writerCount + readerCount, [&](int i) { + if (i < writerCount) + writer(i); + else + reader(); + }); +} + +// Test readers and writers, with readers taking lots of snapshots, and +// simultaneous clearing. +TEST(ConcurrentReadableHashMapTest, MultiThreaded4) { + const int writerCount = 16; + const int readerCount = 8; + const int insertCount = 10000; + + ConcurrentReadableHashMap map; + + std::atomic writerDoneCount = {0}; + auto writer = [&](int threadNumber) { + for (int i = 0; i < insertCount; i++) + map.getOrInsert(MultiThreadedKey{threadNumber, i}, [&](MultiThreadedValue + *value, + bool created) { + [&] { ASSERT_TRUE(created); }(); + new (value) MultiThreadedValue(MultiThreadedKey{threadNumber, i}, i); + return true; + }); + writerDoneCount.fetch_add(1, std::memory_order_relaxed); + }; + + auto reader = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + for (int threadNumber = 0; threadNumber < writerCount; threadNumber++) { + // With clearing, we can't expect any particular pattern. Just validate + // the values we do see, and make sure we don't crash. + for (int i = insertCount - 1; i >= 0; i--) { + auto snapshot = map.snapshot(); + MultiThreadedKey key = {threadNumber, i}; + const MultiThreadedValue *value = snapshot.find(key); + if (value) { + ASSERT_EQ(value->x, i); + } + } + } + } + }; + + auto clear = [&] { + while (writerDoneCount.load(std::memory_order_relaxed) < writerCount) { + map.clear(); + } + }; + + threadedExecute(writerCount + readerCount + 1, [&](int i) { + if (i < writerCount) + writer(i); + else if (i < writerCount + readerCount) + reader(); + else + clear(); + }); +} From 0f879c449ec6bb2fb178025e1039635ea3306a5b Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 20 Aug 2020 11:20:01 -0700 Subject: [PATCH 255/663] [CodeCompletion] Avoid prioritizing unavailable in LookupVisibleDecls rdar://problem/67155695 --- lib/Sema/LookupVisibleDecls.cpp | 27 ++++--- test/IDE/complete_rdar67155695.swift | 111 +++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 test/IDE/complete_rdar67155695.swift diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index cc1ef792f5c92..53bb7c8c57512 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -946,17 +946,22 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer { /*wouldConflictInSwift5*/nullptr, /*skipProtocolExtensionCheck*/true)) { FoundConflicting = true; - // Prefer derived requirements over their witnesses. - if (Reason == - DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal || - VD->getFormalAccess() > OtherVD->getFormalAccess() || - //Prefer available one. - (!AvailableAttr::isUnavailable(VD) && - AvailableAttr::isUnavailable(OtherVD))) { - FilteredResults.remove( - FoundDeclTy(OtherVD, DeclVisibilityKind::LocalVariable, {})); - FilteredResults.insert(DeclAndReason); - *I = VD; + + if (!AvailableAttr::isUnavailable(VD)) { + bool preferVD = ( + // Prefer derived requirements over their witnesses. + Reason == DeclVisibilityKind:: + MemberOfProtocolDerivedByCurrentNominal || + // Prefer available one. + AvailableAttr::isUnavailable(OtherVD) || + // Prefer more accessible one. + VD->getFormalAccess() > OtherVD->getFormalAccess()); + if (preferVD) { + FilteredResults.remove( + FoundDeclTy(OtherVD, DeclVisibilityKind::LocalVariable, {})); + FilteredResults.insert(DeclAndReason); + *I = VD; + } } } } diff --git a/test/IDE/complete_rdar67155695.swift b/test/IDE/complete_rdar67155695.swift new file mode 100644 index 0000000000000..9682653b1f662 --- /dev/null +++ b/test/IDE/complete_rdar67155695.swift @@ -0,0 +1,111 @@ +// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=PUBLIC | %FileCheck %s --check-prefix=PUBLIC +// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=INTERNAL | %FileCheck %s --check-prefix=INTERNAL +// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=PRIVATE | %FileCheck %s --check-prefix=PRIVATE + +public protocol PubP {} + +public extension PubP { + func availableP_availableC() {} + + func availableP_unavailableC() {} + + @available(*, unavailable) + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +struct TestForPubP: PubP { + func availableP_availableC() {} + + @available(*, unavailable) + func availableP_unavailableC() {} + + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +func test(val: TestForPubP) { + val.#^PUBLIC^# +// PUBLIC: Begin completions, 4 items +// PUBLIC-DAG: Keyword[self]/CurrNominal: self[#TestForPubP#]; +// PUBLIC-DAG: Decl[InstanceMethod]/CurrNominal: unavailableP_availableC()[#Void#]; +// PUBLIC-DAG: Decl[InstanceMethod]/Super: availableP_availableC()[#Void#]; +// PUBLIC-DAG: Decl[InstanceMethod]/Super: availableP_unavailableC()[#Void#]; +// PUBLIC: End completions +} + +protocol InternalP {} + +extension InternalP { + func availableP_availableC() {} + + func availableP_unavailableC() {} + + @available(*, unavailable) + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +struct TestForInternalP: InternalP { + func availableP_availableC() {} + + @available(*, unavailable) + func availableP_unavailableC() {} + + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +func test(val: TestForInternalP) { + val.#^INTERNAL^# +// INTERNAL: Begin completions, 4 items +// INTERNAL-DAG: Keyword[self]/CurrNominal: self[#TestForInternalP#]; +// INTERNAL-DAG: Decl[InstanceMethod]/CurrNominal: availableP_availableC()[#Void#]; +// INTERNAL-DAG: Decl[InstanceMethod]/CurrNominal: unavailableP_availableC()[#Void#]; +// INTERNAL-DAG: Decl[InstanceMethod]/Super: availableP_unavailableC()[#Void#]; +// INTERNAL: End completions +} + +private protocol PrivP {} + +private extension PrivP { + func availableP_availableC() {} + + func availableP_unavailableC() {} + + @available(*, unavailable) + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +struct TestForPrivP: PrivP { + func availableP_availableC() {} + + @available(*, unavailable) + func availableP_unavailableC() {} + + func unavailableP_availableC() {} + + @available(*, unavailable) + func unavailableP_unavailableC() {} +} + +func test(val: TestForPrivP) { + val.#^PRIVATE^# +// PRIVATE: Begin completions, 4 items +// PRIVATE-DAG: Keyword[self]/CurrNominal: self[#TestForPrivP#]; +// PRIVATE-DAG: Decl[InstanceMethod]/CurrNominal: availableP_availableC()[#Void#]; +// PRIVATE-DAG: Decl[InstanceMethod]/CurrNominal: unavailableP_availableC()[#Void#]; +// PRIVATE-DAG: Decl[InstanceMethod]/Super: availableP_unavailableC()[#Void#]; +// PRIVATE-DAG: End completions +} From fc4ef192ae875d979365513a03c9f8312f9ba75e Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 20 Aug 2020 11:10:55 -0700 Subject: [PATCH 256/663] [build-script] Add a default-enabled "clean" step for swift-driver and swiftpm Along with options to disable the mandatory clean using: `--skip-clean-swift-driver` and `--skip-clean-swiftpm`. This will ensure that every invocation of build-script will, by default, clean up all build artifacts of these projects and re-build them from scratch. This is needed for all builds because today arbitrary changes to the compiler can lead to us being unable to incrementally build components that are themselves written in Swift. This causes now-frequent failures in incremental build bots, and is a scenario that is encountered by developers. (For example see: rdar://65006593) The proper long-term solution is to enable library evolution for these projects. Until this is done, the only safe thing to do is to always rebuild them. Resolves rdar://65006593 --- utils/build-script | 3 +++ utils/build_swift/build_swift/driver_arguments.py | 4 ++++ utils/build_swift/tests/expected_options.py | 4 ++++ .../swift_build_support/products/product.py | 14 ++++++++++++++ .../swift_build_support/products/swiftdriver.py | 7 +++++++ .../swift_build_support/products/swiftpm.py | 11 +++++++++++ 6 files changed, 43 insertions(+) diff --git a/utils/build-script b/utils/build-script index 84417ed56153a..10ee8f7efd235 100755 --- a/utils/build-script +++ b/utils/build-script @@ -964,6 +964,9 @@ class BuildScriptInvocation(object): toolchain=self.toolchain, source_dir=self.workspace.source_dir(product_source), build_dir=build_dir) + if product.should_clean(host_target): + print("--- Cleaning %s ---" % product_name) + product.clean(host_target) if product.should_build(host_target): print("--- Building %s ---" % product_name) product.build(host_target) diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 838aa5afa84ff..acf339a22c277 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -1008,6 +1008,10 @@ def create_argument_parser(): help='skip testing Android device targets on the host machine (the ' 'phone itself)') + option('--skip-clean-swiftpm', toggle_false('clean_swiftpm'), + help='skip cleaning up swiftpm') + option('--skip-clean-swift-driver', toggle_false('clean_swift_driver'), + help='skip cleaning up Swift driver') option('--skip-test-swiftpm', toggle_false('test_swiftpm'), help='skip testing swiftpm') option('--skip-test-swift-driver', toggle_false('test_swift_driver'), diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py index 9864063b6e7bb..e0381cb842fc2 100644 --- a/utils/build_swift/tests/expected_options.py +++ b/utils/build_swift/tests/expected_options.py @@ -205,6 +205,8 @@ defaults.SWIFT_MAX_PARALLEL_LTO_LINK_JOBS, 'swift_user_visible_version': defaults.SWIFT_USER_VISIBLE_VERSION, 'symbols_package': None, + 'clean_swiftpm': True, + 'clean_swift_driver': True, 'test': None, 'test_android': False, 'test_android_host': False, @@ -567,6 +569,8 @@ class BuildScriptImplOption(_BaseOption): dest='build_watchos_device'), DisableOption('--skip-build-watchos-simulator', dest='build_watchos_simulator'), + DisableOption('--skip-clean-swiftpm', dest='clean_swiftpm'), + DisableOption('--skip-clean-swift-driver', dest='clean_swift_driver'), DisableOption('--skip-test-android', dest='test_android'), DisableOption('--skip-test-android-host', dest='test_android_host'), DisableOption('--skip-test-cygwin', dest='test_cygwin'), diff --git a/utils/swift_build_support/swift_build_support/products/product.py b/utils/swift_build_support/swift_build_support/products/product.py index ed4c944bc008e..5ccfa48283e88 100644 --- a/utils/swift_build_support/swift_build_support/products/product.py +++ b/utils/swift_build_support/swift_build_support/products/product.py @@ -78,6 +78,20 @@ def get_dependencies(cls): """Return a list of products that this product depends upon""" raise NotImplementedError + def should_clean(self, host_target): + """should_clean() -> Bool + + Whether or not this product should be cleaned before being built + """ + return False + + def clean(self, host_target): + """clean() -> void + + Perform the clean, for a non-build-script-impl product. + """ + raise NotImplementedError + def should_build(self, host_target): """should_build() -> Bool diff --git a/utils/swift_build_support/swift_build_support/products/swiftdriver.py b/utils/swift_build_support/swift_build_support/products/swiftdriver.py index 52ca78d4c00a9..5eca23c888086 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftdriver.py +++ b/utils/swift_build_support/swift_build_support/products/swiftdriver.py @@ -47,6 +47,13 @@ def get_dependencies(cls): xctest.XCTest, llbuild.LLBuild] + def should_clean(self, host_target): + return self.args.clean_swift_driver + + def clean(self, host_target): + indexstoredb.run_build_script_helper( + 'clean', host_target, self, self.args) + def build(self, host_target): indexstoredb.run_build_script_helper( 'build', host_target, self, self.args) diff --git a/utils/swift_build_support/swift_build_support/products/swiftpm.py b/utils/swift_build_support/swift_build_support/products/swiftpm.py index 48c18256629b5..412dc52814f5c 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftpm.py +++ b/utils/swift_build_support/swift_build_support/products/swiftpm.py @@ -51,6 +51,11 @@ def run_bootstrap_script(self, action, host_target, additional_params=[]): helper_cmd = [script_path, action] + if action == 'clean': + helper_cmd += ["--build-dir", self.build_dir] + shell.call(helper_cmd) + return + if self.is_release(): helper_cmd.append("--release") @@ -94,6 +99,12 @@ def should_test(self, host_target): def test(self, host_target): self.run_bootstrap_script('test', host_target) + def should_clean(self, host_target): + return self.args.clean_swiftpm + + def clean(self, host_target): + self.run_bootstrap_script('clean', host_target) + def should_install(self, host_target): return self.args.install_swiftpm From 9ffddc9ba63d599d64a76e449b88b7bc13fb4ecd Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 20 Aug 2020 11:31:07 -0700 Subject: [PATCH 257/663] [Function builders] Remove buildDo. "do" blocks will always go through buildBlock(). --- include/swift/AST/KnownIdentifiers.def | 1 - lib/Sema/BuilderTransform.cpp | 14 ++------------ test/Constraints/function_builder.swift | 18 +----------------- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index a9e0f46cb4783..37898169a6707 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -33,7 +33,6 @@ IDENTIFIER(atIndexedSubscript) IDENTIFIER_(bridgeToObjectiveC) IDENTIFIER(buildArray) IDENTIFIER(buildBlock) -IDENTIFIER(buildDo) IDENTIFIER(buildEither) IDENTIFIER(buildExpression) IDENTIFIER(buildFinalResult) diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 6e8c291c9b36b..891a6c503262b 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -310,10 +310,6 @@ class BuilderClosureVisitor } VarDecl *visitBraceStmt(BraceStmt *braceStmt) { - return visitBraceStmt(braceStmt, ctx.Id_buildBlock); - } - - VarDecl *visitBraceStmt(BraceStmt *braceStmt, Identifier builderFunction) { SmallVector expressions; auto addChild = [&](VarDecl *childVar) { if (!childVar) @@ -380,7 +376,7 @@ class BuilderClosureVisitor // Call Builder.buildBlock(... args ...) auto call = buildCallIfWanted(braceStmt->getStartLoc(), - builderFunction, expressions, + ctx.Id_buildBlock, expressions, /*argLabels=*/{ }); if (!call) return nullptr; @@ -395,13 +391,7 @@ class BuilderClosureVisitor } VarDecl *visitDoStmt(DoStmt *doStmt) { - if (!builderSupports(ctx.Id_buildDo)) { - if (!unhandledNode) - unhandledNode = doStmt; - return nullptr; - } - - auto childVar = visitBraceStmt(doStmt->getBody(), ctx.Id_buildDo); + auto childVar = visitBraceStmt(doStmt->getBody()); if (!childVar) return nullptr; diff --git a/test/Constraints/function_builder.swift b/test/Constraints/function_builder.swift index f59372bd0ff7f..b04707396af9b 100644 --- a/test/Constraints/function_builder.swift +++ b/test/Constraints/function_builder.swift @@ -36,19 +36,6 @@ struct TupleBuilder { return (t1, t2, t3, t4, t5) } - static func buildDo(_ t1: T1) -> Do<(T1)> { - .init(value: t1) - } - - static func buildDo(_ t1: T1, _ t2: T2) -> Do<(T1, T2)> { - .init(value: (t1, t2)) - } - - static func buildDo(_ t1: T1, _ t2: T2, _ t3: T3) - -> Do<(T1, T2, T3)> { - .init(value: (t1, t2, t3)) - } - static func buildIf(_ value: T?) -> T? { return value } static func buildEither(first value: T) -> Either { @@ -65,7 +52,7 @@ func tuplify(_ cond: Bool, @TupleBuilder body: (Bool) -> T) { print(body(cond)) } -// CHECK: (17, 3.14159, "Hello, DSL", main.Do<(Swift.Array, Swift.Int)>(value: (["nested", "do"], 6)), Optional((2.71828, ["if", "stmt"]))) +// CHECK: (17, 3.14159, "Hello, DSL", (["nested", "do"], 6), Optional((2.71828, ["if", "stmt"]))) let name = "dsl" tuplify(true) { 17 @@ -664,7 +651,6 @@ struct TupleBuilderWithOpt { return (t1, t2, t3, t4, t5) } - static func buildDo(_ value: T) -> T { return value } static func buildOptional(_ value: T?) -> T? { return value } static func buildEither(first value: T) -> Either { @@ -718,7 +704,6 @@ protocol FunctionBuilderProtocol { static func buildExpression(_ expression: Expression) -> Component static func buildBlock(_ components: Component...) -> Component - static func buildDo(_ components: Component...) -> Component static func buildOptional(_ optional: Component?) -> Component static func buildArray(_ components: [Component]) -> Component static func buildLimitedAvailability(_ component: Component) -> Component @@ -729,7 +714,6 @@ protocol FunctionBuilderProtocol { extension FunctionBuilderProtocol { static func buildExpression(_ expression: Expression) -> Component { .expression(expression) } static func buildBlock(_ components: Component...) -> Component { .block(components) } - static func buildDo(_ components: Component...) -> Component { .block(components) } static func buildOptional(_ optional: Component?) -> Component { .optional(optional) } static func buildArray(_ components: [Component]) -> Component { .block(components) } static func buildLimitedAvailability(_ component: Component) -> Component { component } From 1a90eccbfaab62c8168a4e98329d4f42c7abcd0d Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 20 Aug 2020 11:52:25 -0700 Subject: [PATCH 258/663] [Function builders] Remove test case residue. --- test/Constraints/function_builder.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/Constraints/function_builder.swift b/test/Constraints/function_builder.swift index b04707396af9b..d095f852a5d56 100644 --- a/test/Constraints/function_builder.swift +++ b/test/Constraints/function_builder.swift @@ -6,10 +6,6 @@ enum Either { case second(U) } -struct Do { - var value: T -} - @_functionBuilder struct TupleBuilder { static func buildBlock(_ t1: T1) -> (T1) { From d46c4ec5c5b62834c105ea22582f6d6dc2cc5437 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 20 Aug 2020 12:11:45 -0700 Subject: [PATCH 259/663] [Function builders] Add support for 'throw' statement. --- lib/Sema/BuilderTransform.cpp | 46 ++++++++++++++++++- test/Constraints/function_builder.swift | 22 ++++++++- test/Constraints/function_builder_diags.swift | 12 +++++ 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 891a6c503262b..b7f917dc51f81 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -896,6 +896,26 @@ class BuilderClosureVisitor return finalForEachVar; } + /// Visit a throw statement, which never produces a result. + VarDecl *visitThrowStmt(ThrowStmt *throwStmt) { + Type exnType = ctx.getErrorDecl()->getDeclaredInterfaceType(); + if (!exnType) { + hadError = true; + } + + if (cs) { + SolutionApplicationTarget target( + throwStmt->getSubExpr(), dc, CTP_ThrowStmt, exnType, + /*isDiscarded=*/false); + if (cs->generateConstraints(target, FreeTypeVariableBinding::Disallow)) + hadError = true; + + cs->setSolutionApplicationTarget(throwStmt, target); + } + + return nullptr; + } + CONTROL_FLOW_STMT(Guard) CONTROL_FLOW_STMT(While) CONTROL_FLOW_STMT(DoCatch) @@ -905,7 +925,6 @@ class BuilderClosureVisitor CONTROL_FLOW_STMT(Continue) CONTROL_FLOW_STMT(Fallthrough) CONTROL_FLOW_STMT(Fail) - CONTROL_FLOW_STMT(Throw) CONTROL_FLOW_STMT(PoundAssert) #undef CONTROL_FLOW_STMT @@ -1141,6 +1160,14 @@ class BuilderClosureRewriter } if (auto stmt = node.dyn_cast()) { + // "throw" statements produce no value. Transform them directly. + if (auto throwStmt = dyn_cast(stmt)) { + if (auto newStmt = visitThrowStmt(throwStmt)) { + newElements.push_back(stmt); + } + continue; + } + // Each statement turns into a (potential) temporary variable // binding followed by the statement itself. auto captured = takeCapturedStmt(stmt); @@ -1429,6 +1456,22 @@ class BuilderClosureRewriter ctx, forEachStmt->getStartLoc(), outerBodySteps, newBody->getEndLoc()); } + Stmt *visitThrowStmt(ThrowStmt *throwStmt) { + // Rewrite the error. + auto target = *solution.getConstraintSystem() + .getSolutionApplicationTarget(throwStmt); + if (auto result = rewriteTarget(target)) + throwStmt->setSubExpr(result->getAsExpr()); + else + return nullptr; + + return throwStmt; + } + + Stmt *visitThrowStmt(ThrowStmt *throwStmt, FunctionBuilderTarget target) { + llvm_unreachable("Throw statements produce no value"); + } + #define UNHANDLED_FUNCTION_BUILDER_STMT(STMT) \ Stmt *visit##STMT##Stmt(STMT##Stmt *stmt, FunctionBuilderTarget target) { \ llvm_unreachable("Function builders do not allow statement of kind " \ @@ -1446,7 +1489,6 @@ class BuilderClosureRewriter UNHANDLED_FUNCTION_BUILDER_STMT(Continue) UNHANDLED_FUNCTION_BUILDER_STMT(Fallthrough) UNHANDLED_FUNCTION_BUILDER_STMT(Fail) - UNHANDLED_FUNCTION_BUILDER_STMT(Throw) UNHANDLED_FUNCTION_BUILDER_STMT(PoundAssert) #undef UNHANDLED_FUNCTION_BUILDER_STMT }; diff --git a/test/Constraints/function_builder.swift b/test/Constraints/function_builder.swift index d095f852a5d56..d30a3a932f7ce 100644 --- a/test/Constraints/function_builder.swift +++ b/test/Constraints/function_builder.swift @@ -44,8 +44,8 @@ struct TupleBuilder { static func buildArray(_ array: [T]) -> [T] { return array } } -func tuplify(_ cond: Bool, @TupleBuilder body: (Bool) -> T) { - print(body(cond)) +func tuplify(_ cond: Bool, @TupleBuilder body: (Bool) throws -> T) rethrows { + print(try body(cond)) } // CHECK: (17, 3.14159, "Hello, DSL", (["nested", "do"], 6), Optional((2.71828, ["if", "stmt"]))) @@ -749,3 +749,21 @@ let a = buildArray { // CHECK: ["1", "2" print(a) +// Throwing in function builders. +enum MyError: Error { + case boom +} + +// CHECK: testThrow +do { + print("testThrow") + try tuplify(true) { c in + "ready to throw" + throw MyError.boom + } +} catch MyError.boom { + // CHECK: caught it! + print("caught it!") +} catch { + fatalError("Threw something else?") +} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 7a7029b499935..ee93f2076c085 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -620,3 +620,15 @@ struct MyView { "" } } + +// Make sure throwing function builder closures are implied. +enum MyError: Error { + case boom +} + +do { + tuplify(true) { c in // expected-error{{invalid conversion from throwing function of type '(Bool) throws -> String' to non-throwing function type '(Bool) -> String'}} + "testThrow" + throw MyError.boom + } +} From e13217147f7ba702f2373a77f91478ae222fe178 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 20 Aug 2020 15:55:38 -0400 Subject: [PATCH 260/663] [Test] Filter out a __rotate symbol and another __once_call symbol in symbol-visibility-linux.test-sh. --- test/stdlib/symbol-visibility-linux.test-sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/stdlib/symbol-visibility-linux.test-sh b/test/stdlib/symbol-visibility-linux.test-sh index 62be057f4d919..86a7a6dab377d 100644 --- a/test/stdlib/symbol-visibility-linux.test-sh +++ b/test/stdlib/symbol-visibility-linux.test-sh @@ -19,6 +19,7 @@ // RUN: -e _ZNSt6vectorIjSaIjEE13_M_insert_auxIJjEEEvN9__gnu_cxx17__normal_iteratorIPjS1_EEDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE19_M_emplace_back_auxIJS6_EEEvDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE17_M_realloc_insertIJS6_EEEvN9__gnu_cxx17__normal_iteratorIPS6_S8_EEDpOT_ \ +// RUN: -e _ZNSt3_V28__rotateIPcEET_S2_S2_S2_St26random_access_iterator_tag \ // RUN: -e _ZN9__gnu_cxx12__to_xstringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEcEET_PFiPT0_mPKS8_P13__va_list_tagEmSB_z \ // RUN: -e _ZZNSt19_Sp_make_shared_tag5_S_tiEvE5__tag \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEDnEEEvv \ @@ -30,6 +31,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftCore-all.txt // RUN: %llvm-nm --defined-only --extern-only --no-weak %platform-dylib-dir/%target-library-name(swiftCore) > %t/swiftCore-no-weak.txt @@ -41,6 +43,7 @@ // RUN: -e _ZNSt6vectorIjSaIjEE13_M_insert_auxIJjEEEvN9__gnu_cxx17__normal_iteratorIPjS1_EEDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE19_M_emplace_back_auxIJS6_EEEvDpOT_ \ // RUN: -e _ZNSt6vectorISt10unique_ptrIKvSt8functionIFvPS1_EEESaIS6_EE17_M_realloc_insertIJS6_EEEvN9__gnu_cxx17__normal_iteratorIPS6_S8_EEDpOT_ \ +// RUN: -e _ZNSt3_V28__rotateIPcEET_S2_S2_S2_St26random_access_iterator_tag \ // RUN: -e _ZN9__gnu_cxx12__to_xstringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEcEET_PFiPT0_mPKS8_P13__va_list_tagEmSB_z \ // RUN: -e _ZZNSt19_Sp_make_shared_tag5_S_tiEvE5__tag \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEDnEEEvv \ @@ -52,6 +55,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftRemoteMirror-all.txt // RUN: %llvm-nm --defined-only --extern-only --no-weak %platform-dylib-dir/%target-library-name(swiftRemoteMirror) > %t/swiftRemoteMirror-no-weak.txt From 29e655bac03c60a29e1fb95be083a15f557926e4 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 20 Aug 2020 11:45:21 -0700 Subject: [PATCH 261/663] DependenciesScanner: implement protocol for batch module dependencies scan This scanning mode allows swift-driver to query module dependencies in a batch and in a more granular way. In short term, it could help solve a problem that clang module dependencies may vary if target triple changes. In a longer term, we could break a holistic dependencies graph into smaller pieces for better caching and reusing. This change doesn't include the implementation of using the specified scanner arguments to set up Clang dependencies scanner. It will come in later commits. --- include/swift/AST/ASTContext.h | 6 + include/swift/AST/DiagnosticsFrontend.def | 8 + include/swift/AST/SearchPathOptions.h | 3 + include/swift/Option/FrontendOptions.td | 4 + lib/AST/ASTContext.cpp | 15 ++ lib/Frontend/CompilerInvocation.cpp | 3 +- lib/FrontendTool/FrontendTool.cpp | 10 +- lib/FrontendTool/ScanDependencies.cpp | 145 ++++++++++++++++-- lib/FrontendTool/ScanDependencies.h | 5 + test/ScanDependencies/batch_module_scan.swift | 39 +++++ 10 files changed, 225 insertions(+), 13 deletions(-) create mode 100644 test/ScanDependencies/batch_module_scan.swift diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 9ef666affbf7e..9281ebcf55c2b 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -739,6 +739,12 @@ class ASTContext final { ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate); + /// Retrieve the module dependencies for the Swift module with the given name. + Optional getSwiftModuleDependencies( + StringRef moduleName, + ModuleDependenciesCache &cache, + InterfaceSubContextDelegate &delegate); + /// Load extensions to the given nominal type from the external /// module loaders. /// diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 21931481da7be..36471ecbc9d92 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -274,6 +274,14 @@ ERROR(placeholder_dependency_module_map_corrupted,none, "Swift placeholder dependency module map from %0 is malformed", (StringRef)) +ERROR(batch_scan_input_file_missing,none, + "cannot open batch dependencies scan input file from %0", + (StringRef)) + +ERROR(batch_scan_input_file_corrupted,none, + "batch dependencies scan input file from %0 is malformed", + (StringRef)) + REMARK(default_previous_install_name, none, "default previous install name for %0 is %1", (StringRef, StringRef)) diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index 08757ffd796de..52eeace6a1460 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -93,6 +93,9 @@ class SearchPathOptions { /// A map of placeholder Swift module dependency information. std::string PlaceholderDependencyModuleMap; + + /// A file containing modules we should perform batch scanning. + std::string BatchScanInputFilePath; private: static StringRef pathStringFromFrameworkSearchPath(const FrameworkSearchPath &next) { diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 5bd693d2ffe7d..8c00c8a94ca16 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -228,6 +228,10 @@ def explict_swift_module_map def placeholder_dependency_module_map : Separate<["-"], "placeholder-dependency-module-map-file">, MetaVarName<"">, HelpText<"Specify a JSON file containing information of external Swift module dependencies">; + +def batch_scan_input_file + : Separate<["-"], "batch-scan-input-file">, MetaVarName<"">, + HelpText<"Specify a JSON file containing modules to perform batch dependencies scanning">; } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e75c5185cc13b..f3ee9197874a9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1516,6 +1516,21 @@ Optional ASTContext::getModuleDependencies( return None; } +Optional +ASTContext::getSwiftModuleDependencies(StringRef moduleName, + ModuleDependenciesCache &cache, + InterfaceSubContextDelegate &delegate) { + for (auto &loader : getImpl().ModuleLoaders) { + if (loader.get() == getImpl().TheClangModuleLoader) + continue; + + if (auto dependencies = loader->getModuleDependencies(moduleName, cache, + delegate)) + return dependencies; + } + return None; +} + void ASTContext::loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) { PrettyStackTraceDecl stackTrace("loading extensions for", nominal); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f9c3828c19c67..db5894b1d4a20 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -926,7 +926,8 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, } if (const Arg *A = Args.getLastArg(OPT_placeholder_dependency_module_map)) Opts.PlaceholderDependencyModuleMap = A->getValue(); - + if (const Arg *A = Args.getLastArg(OPT_batch_scan_input_file)) + Opts.BatchScanInputFilePath = A->getValue(); // Opts.RuntimeIncludePath is set by calls to // setRuntimeIncludePath() or setMainExecutablePath(). // Opts.RuntimeImportPath is set by calls to diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 9bdfe3e1da24b..063e89e2860d6 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1833,8 +1833,14 @@ static bool performCompile(CompilerInstance &Instance, return finishPipeline(Context.hadError()); } - if (Action == FrontendOptions::ActionType::ScanDependencies) - return finishPipeline(scanDependencies(Instance)); + if (Action == FrontendOptions::ActionType::ScanDependencies) { + auto batchScanInput = Instance.getASTContext().SearchPathOpts.BatchScanInputFilePath; + if (batchScanInput.empty()) + return finishPipeline(scanDependencies(Instance)); + else + return finishPipeline(batchScanModuleDependencies(Instance, + batchScanInput)); + } if (Action == FrontendOptions::ActionType::ScanClangDependencies) return finishPipeline(scanClangDependencies(Instance)); diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index bf2fccc25de93..4a616a69a53dc 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -32,12 +32,101 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/YAMLParser.h" #include using namespace swift; +using namespace llvm::yaml; namespace { +struct BatchScanInput { + StringRef moduleName; + StringRef arguments; + StringRef outputPath; +}; + +static std::string getScalaNodeText(Node *N) { + SmallString<32> Buffer; + return cast(N)->getValue(Buffer).str(); +} + +/// Parse an entry like this, where the "platforms" key-value pair is optional: +/// { +/// "module": "Foo.pcm", +/// "arguments": "-target 10.15", +/// "output": "../Foo.json" +/// }, +static bool parseBatchInputEntries(ASTContext &Ctx, llvm::StringSaver &saver, + Node *Node, std::vector &result) { + auto *SN = cast(Node); + if (!SN) + return true; + for (auto It = SN->begin(); It != SN->end(); ++It) { + auto *MN = cast(&*It); + BatchScanInput entry; + Optional> Platforms; + for (auto &Pair: *MN) { + auto Key = getScalaNodeText(Pair.getKey()); + auto* Value = Pair.getValue(); + if (Key == "module") { + entry.moduleName = saver.save(getScalaNodeText(Value)); + } else if (Key == "arguments") { + entry.arguments = saver.save(getScalaNodeText(Value)); + } else if (Key == "output") { + entry.outputPath = saver.save(getScalaNodeText(Value)); + } else { + // Future proof. + continue; + } + } + if (entry.moduleName.empty()) + return true; + if (entry.outputPath.empty()) + return true; + auto ext = llvm::sys::path::extension(entry.moduleName); + if (ext != ".swiftmodule" && ext != ".pcm") + return true; + result.emplace_back(std::move(entry)); + } + return false; +} +static Optional> +parseBatchScanInputFile(ASTContext &ctx, StringRef batchInputPath, + llvm::StringSaver &saver) { + assert(!batchInputPath.empty()); + namespace yaml = llvm::yaml; + std::vector result; + + // Load the input file. + llvm::ErrorOr> FileBufOrErr = + llvm::MemoryBuffer::getFile(batchInputPath); + if (!FileBufOrErr) { + ctx.Diags.diagnose(SourceLoc(), diag::batch_scan_input_file_missing, + batchInputPath); + return None; + } + StringRef Buffer = FileBufOrErr->get()->getBuffer(); + + // Use a new source manager instead of the one from ASTContext because we + // don't want the Json file to be persistent. + SourceManager SM; + yaml::Stream Stream(llvm::MemoryBufferRef(Buffer, batchInputPath), + SM.getLLVMSourceMgr()); + for (auto DI = Stream.begin(); DI != Stream.end(); ++ DI) { + assert(DI != Stream.end() && "Failed to read a document"); + yaml::Node *N = DI->getRoot(); + assert(N && "Failed to find a root"); + if (parseBatchInputEntries(ctx, saver, N, result)) { + ctx.Diags.diagnose(SourceLoc(), diag::batch_scan_input_file_corrupted, + batchInputPath); + return None; + } + } + return result; +} } /// Find all of the imported Clang modules starting with the given module name. @@ -533,15 +622,17 @@ static bool diagnoseCycle(CompilerInstance &instance, return false; } -bool swift::scanClangDependencies(CompilerInstance &instance) { +static bool scanModuleDependencies(CompilerInstance &instance, + StringRef moduleName, + StringRef arguments, + bool isClang, + StringRef outputPath) { ASTContext &ctx = instance.getASTContext(); - ModuleDecl *mainModule = instance.getMainModule(); auto &FEOpts = instance.getInvocation().getFrontendOptions(); ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); auto ModuleCachePath = getModuleCachePathFromClang(ctx .getClangModuleLoader()->getClangInstance()); - StringRef mainModuleName = mainModule->getNameStr(); llvm::SetVector, std::set> allModules; // Create the module dependency cache. @@ -555,16 +646,23 @@ bool swift::scanClangDependencies(CompilerInstance &instance) { FEOpts.PrebuiltModuleCachePath, FEOpts.SerializeModuleInterfaceDependencyHashes, FEOpts.shouldTrackSystemDependencies()); - // Loading the clang module using Clang importer. - // This action will populate the cache with the main module's dependencies. - auto rootDeps = static_cast(ctx.getClangModuleLoader()) - ->getModuleDependencies(mainModuleName, cache, ASTDelegate); + Optional rootDeps; + if (isClang) { + // Loading the clang module using Clang importer. + // This action will populate the cache with the main module's dependencies. + rootDeps = ctx.getModuleDependencies(moduleName, /*IsClang*/true, cache, + ASTDelegate); + } else { + // Loading the swift module's dependencies. + rootDeps = ctx.getSwiftModuleDependencies(moduleName, cache, ASTDelegate); + } if (!rootDeps.hasValue()) { // We cannot find the clang module, abort. return true; } // Add the main module. - allModules.insert({mainModuleName.str(), ModuleDependenciesKind::Clang}); + allModules.insert({moduleName.str(), isClang ? ModuleDependenciesKind::Clang: + ModuleDependenciesKind::Swift}); // Explore the dependencies of every module. for (unsigned currentModuleIdx = 0; @@ -576,13 +674,40 @@ bool swift::scanClangDependencies(CompilerInstance &instance) { allModules.insert(discoveredModules.begin(), discoveredModules.end()); } // Write out the JSON description. - std::string path = FEOpts.InputsAndOutputs.getSingleOutputFilename(); std::error_code EC; - llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None); + llvm::raw_fd_ostream out(outputPath, EC, llvm::sys::fs::F_None); writeJSON(out, instance, cache, ASTDelegate, allModules.getArrayRef()); return false; } +bool swift::scanClangDependencies(CompilerInstance &instance) { + return scanModuleDependencies(instance, + instance.getMainModule()->getNameStr(), + StringRef(), + /*isClang*/true, + instance.getInvocation().getFrontendOptions() + .InputsAndOutputs.getSingleOutputFilename()); +} + +bool swift::batchScanModuleDependencies(CompilerInstance &instance, + llvm::StringRef batchInputFile) { + (void)instance.getMainModule(); + llvm::BumpPtrAllocator alloc; + llvm::StringSaver saver(alloc); + auto results = parseBatchScanInputFile(instance.getASTContext(), + batchInputFile, saver); + if (!results.hasValue()) + return true; + for (auto &entry: *results) { + auto moduleName = llvm::sys::path::stem(entry.moduleName); + auto isClang = llvm::sys::path::extension(entry.moduleName) == ".pcm"; + if (scanModuleDependencies(instance, moduleName, entry.arguments, isClang, + entry.outputPath)) + return true; + } + return false; +} + bool swift::scanDependencies(CompilerInstance &instance) { ASTContext &Context = instance.getASTContext(); ModuleDecl *mainModule = instance.getMainModule(); diff --git a/lib/FrontendTool/ScanDependencies.h b/lib/FrontendTool/ScanDependencies.h index e3ed171c2badb..d4e0cf1a2c544 100644 --- a/lib/FrontendTool/ScanDependencies.h +++ b/lib/FrontendTool/ScanDependencies.h @@ -13,10 +13,15 @@ #ifndef SWIFT_FRONTENDTOOL_SCANDEPENDENCIES_H #define SWIFT_FRONTENDTOOL_SCANDEPENDENCIES_H +#include "llvm/ADT/StringRef.h" + namespace swift { class CompilerInstance; +/// Batch scan the dependencies for modules specified in \c batchInputFile. +bool batchScanModuleDependencies(CompilerInstance &instance, llvm::StringRef batchInputFile); + /// Scans the dependencies of the main module of \c instance. bool scanDependencies(CompilerInstance &instance); diff --git a/test/ScanDependencies/batch_module_scan.swift b/test/ScanDependencies/batch_module_scan.swift new file mode 100644 index 0000000000000..a6fb01313fedb --- /dev/null +++ b/test/ScanDependencies/batch_module_scan.swift @@ -0,0 +1,39 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: %empty-directory(%t/outputs) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: echo "[{" > %/t/inputs/input.json +// RUN: echo "\"module\": \"F.swiftmodule\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/F.swiftmodule.json\"" >> %/t/inputs/input.json +// RUN: echo "}," >> %/t/inputs/input.json +// RUN: echo "{" >> %/t/inputs/input.json +// RUN: echo "\"module\": \"F.pcm\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/F.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}]" >> %/t/inputs/input.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix=CHECK-PCM < %t/outputs/F.pcm.json +// RUN: %FileCheck %s -check-prefix=CHECK-SWIFT < %t/outputs/F.swiftmodule.json + +// CHECK-PCM: { +// CHECK-PCM-NEXT: "mainModuleName": "F", +// CHECK-PCM-NEXT: "modules": [ +// CHECK-PCM-NEXT: { +// CHECK-PCM-NEXT: "clang": "F" +// CHECK-PCM-NEXT: }, +// CHECK-PCM-NEXT: { +// CHECK-PCM-NEXT: "modulePath": "F.pcm", + +// CHECK-SWIFT: { +// CHECK-SWIFT-NEXT: "mainModuleName": "F", +// CHECK-SWIFT-NEXT: "modules": [ +// CHECK-SWIFT-NEXT: { +// CHECK-SWIFT-NEXT: "swift": "F" +// CHECK-SWIFT-NEXT: }, +// CHECK-SWIFT-NEXT: { +// CHECK-SWIFT-NEXT: "modulePath": "F.swiftmodule", From 32e030547f513c9fa7d71a7d5521b37e39a80c66 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 20 Aug 2020 14:40:30 -0700 Subject: [PATCH 262/663] [NFC] Add test for self-cycles in module trace. --- .../Inputs/imported_modules/SelfImport/module.modulemap | 6 ++++++ test/Driver/loaded_module_trace_self_cycle.swift | 4 ++++ 2 files changed, 10 insertions(+) create mode 100644 test/Driver/Inputs/imported_modules/SelfImport/module.modulemap create mode 100644 test/Driver/loaded_module_trace_self_cycle.swift diff --git a/test/Driver/Inputs/imported_modules/SelfImport/module.modulemap b/test/Driver/Inputs/imported_modules/SelfImport/module.modulemap new file mode 100644 index 0000000000000..df67010362525 --- /dev/null +++ b/test/Driver/Inputs/imported_modules/SelfImport/module.modulemap @@ -0,0 +1,6 @@ +module Outer { + module Inner { + export Outer.Inner + } + export Outer +} diff --git a/test/Driver/loaded_module_trace_self_cycle.swift b/test/Driver/loaded_module_trace_self_cycle.swift new file mode 100644 index 0000000000000..6450956312932 --- /dev/null +++ b/test/Driver/loaded_module_trace_self_cycle.swift @@ -0,0 +1,4 @@ +// Check that this doesn't crash due to a self-cycle. rdar://67435472 +// RUN: not --crash %target-swift-frontend %s -emit-module -o /dev/null -emit-loaded-module-trace-path /dev/null -I %S/Inputs/imported_modules/SelfImport + +import Outer From 6a6b1f832d2c9cc9f3a89f2d38729845edeb08ac Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 20 Aug 2020 14:40:54 -0700 Subject: [PATCH 263/663] DependenciesScanner: differentiate Swift and Clang module more explicitly in batch scan input --- lib/FrontendTool/ScanDependencies.cpp | 18 +++++++++--------- test/ScanDependencies/batch_module_scan.swift | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 4a616a69a53dc..524a5de2213e6 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -45,6 +45,7 @@ struct BatchScanInput { StringRef moduleName; StringRef arguments; StringRef outputPath; + bool isSwift; }; static std::string getScalaNodeText(Node *N) { @@ -54,7 +55,7 @@ static std::string getScalaNodeText(Node *N) { /// Parse an entry like this, where the "platforms" key-value pair is optional: /// { -/// "module": "Foo.pcm", +/// "swiftModuleName": "Foo", /// "arguments": "-target 10.15", /// "output": "../Foo.json" /// }, @@ -70,8 +71,12 @@ static bool parseBatchInputEntries(ASTContext &Ctx, llvm::StringSaver &saver, for (auto &Pair: *MN) { auto Key = getScalaNodeText(Pair.getKey()); auto* Value = Pair.getValue(); - if (Key == "module") { + if (Key == "clangModuleName") { entry.moduleName = saver.save(getScalaNodeText(Value)); + entry.isSwift = false; + } else if (Key == "swiftModuleName") { + entry.moduleName = saver.save(getScalaNodeText(Value)); + entry.isSwift = true; } else if (Key == "arguments") { entry.arguments = saver.save(getScalaNodeText(Value)); } else if (Key == "output") { @@ -85,9 +90,6 @@ static bool parseBatchInputEntries(ASTContext &Ctx, llvm::StringSaver &saver, return true; if (entry.outputPath.empty()) return true; - auto ext = llvm::sys::path::extension(entry.moduleName); - if (ext != ".swiftmodule" && ext != ".pcm") - return true; result.emplace_back(std::move(entry)); } return false; @@ -699,10 +701,8 @@ bool swift::batchScanModuleDependencies(CompilerInstance &instance, if (!results.hasValue()) return true; for (auto &entry: *results) { - auto moduleName = llvm::sys::path::stem(entry.moduleName); - auto isClang = llvm::sys::path::extension(entry.moduleName) == ".pcm"; - if (scanModuleDependencies(instance, moduleName, entry.arguments, isClang, - entry.outputPath)) + if (scanModuleDependencies(instance, entry.moduleName, entry.arguments, + !entry.isSwift, entry.outputPath)) return true; } return false; diff --git a/test/ScanDependencies/batch_module_scan.swift b/test/ScanDependencies/batch_module_scan.swift index a6fb01313fedb..08151fc4eb6f6 100644 --- a/test/ScanDependencies/batch_module_scan.swift +++ b/test/ScanDependencies/batch_module_scan.swift @@ -4,12 +4,12 @@ // RUN: mkdir -p %t/clang-module-cache // RUN: echo "[{" > %/t/inputs/input.json -// RUN: echo "\"module\": \"F.swiftmodule\"," >> %/t/inputs/input.json +// RUN: echo "\"swiftModuleName\": \"F\"," >> %/t/inputs/input.json // RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json // RUN: echo "\"output\": \"%/t/outputs/F.swiftmodule.json\"" >> %/t/inputs/input.json // RUN: echo "}," >> %/t/inputs/input.json // RUN: echo "{" >> %/t/inputs/input.json -// RUN: echo "\"module\": \"F.pcm\"," >> %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"F\"," >> %/t/inputs/input.json // RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json // RUN: echo "\"output\": \"%/t/outputs/F.pcm.json\"" >> %/t/inputs/input.json // RUN: echo "}]" >> %/t/inputs/input.json From 260125e7aeac654273268f16b76e3d65f8b905f8 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 20 Aug 2020 14:53:06 -0700 Subject: [PATCH 264/663] [ModuleTrace] Early exit if a Clang module imports itself. Fixes rdar://67435472. --- lib/FrontendTool/FrontendTool.cpp | 5 +++-- test/Driver/loaded_module_trace_self_cycle.swift | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 9bdfe3e1da24b..7061a2c5d1916 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -588,8 +588,9 @@ void ABIDependencyEvaluator::computeABIDependenciesForClangModule( } if (import->isNonSwiftModule() && module->getTopLevelModule() == import->getTopLevelModule() - && !import->findUnderlyingClangModule() - ->isSubModuleOf(module->findUnderlyingClangModule())) { + && (module == import + || !import->findUnderlyingClangModule() + ->isSubModuleOf(module->findUnderlyingClangModule()))) { continue; } computeABIDependenciesForModule(import); diff --git a/test/Driver/loaded_module_trace_self_cycle.swift b/test/Driver/loaded_module_trace_self_cycle.swift index 6450956312932..309ef714e34bf 100644 --- a/test/Driver/loaded_module_trace_self_cycle.swift +++ b/test/Driver/loaded_module_trace_self_cycle.swift @@ -1,4 +1,4 @@ // Check that this doesn't crash due to a self-cycle. rdar://67435472 -// RUN: not --crash %target-swift-frontend %s -emit-module -o /dev/null -emit-loaded-module-trace-path /dev/null -I %S/Inputs/imported_modules/SelfImport +// RUN: %target-swift-frontend %s -emit-module -o /dev/null -emit-loaded-module-trace-path /dev/null -I %S/Inputs/imported_modules/SelfImport import Outer From 6c18a0388333df9b10b60bbea69b3bcd00afb966 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Wed, 19 Aug 2020 20:50:28 -0700 Subject: [PATCH 265/663] [NFC] Add ClangNode::dump() --- include/swift/AST/ClangNode.h | 3 +++ lib/AST/Decl.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/swift/AST/ClangNode.h b/include/swift/AST/ClangNode.h index cbf120840b661..73a633bacd70e 100644 --- a/include/swift/AST/ClangNode.h +++ b/include/swift/AST/ClangNode.h @@ -13,6 +13,7 @@ #ifndef SWIFT_CLANGNODE_H #define SWIFT_CLANGNODE_H +#include "swift/Basic/Debug.h" #include "llvm/ADT/PointerUnion.h" namespace clang { @@ -98,6 +99,8 @@ class ClangNode { clang::SourceLocation getLocation() const; clang::SourceRange getSourceRange() const; + SWIFT_DEBUG_DUMP; + void *getOpaqueValue() const { return Ptr.getOpaqueValue(); } static inline ClangNode getFromOpaqueValue(void *VP) { ClangNode N; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ad9f3fe3e8f6d..4fdb7199e4ba3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -116,6 +116,17 @@ const clang::Module *ClangNode::getClangModule() const { return nullptr; } +void ClangNode::dump() const { + if (auto D = getAsDecl()) + D->dump(); + else if (auto M = getAsMacro()) + M->dump(); + else if (auto M = getAsModule()) + M->dump(); + else + llvm::errs() << "ClangNode contains nullptr\n"; +} + // Only allow allocation of Decls using the allocator in ASTContext. void *Decl::operator new(size_t Bytes, const ASTContext &C, unsigned Alignment) { From 28ea3e1727a112ef8f84bd427958012e267e5cf5 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Wed, 19 Aug 2020 20:51:24 -0700 Subject: [PATCH 266/663] [NFC] Document TypeAliasDecl::isCompatibilityAlias --- include/swift/AST/Decl.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index cefb000652d63..92d70f2af9083 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2996,11 +2996,29 @@ class TypeAliasDecl : public GenericTypeDecl { /// Retrieve a sugared interface type containing the structure of the interface /// type before any semantic validation has occured. Type getStructuralType() const; - + + /// Whether the typealias forwards perfectly to its underlying type. + /// + /// If true, this typealias was created by ClangImporter to preserve source + /// compatibility with a previous language version's name for a type. Many + /// checks in Sema look through compatibility aliases even when they would + /// operate on other typealiases. + /// + /// \warning This has absolutely nothing to do with the Objective-C + /// \c compatibility_alias keyword. bool isCompatibilityAlias() const { return Bits.TypeAliasDecl.IsCompatibilityAlias; } + /// Sets whether the typealias forwards perfectly to its underlying type. + /// + /// Marks this typealias as having been created by ClangImporter to preserve + /// source compatibility with a previous language version's name for a type. + /// Many checks in Sema look through compatibility aliases even when they + /// would operate on other typealiases. + /// + /// \warning This has absolutely nothing to do with the Objective-C + /// \c compatibility_alias keyword. void markAsCompatibilityAlias(bool newValue = true) { Bits.TypeAliasDecl.IsCompatibilityAlias = newValue; } From 9d4281b46b31cb10b678fdd8b574ab05ff161d27 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Thu, 20 Aug 2020 16:19:31 -0700 Subject: [PATCH 267/663] Support generic @compatibility_alias in PrintAsObjC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When @compatibility_alias is used with an ObjC generic class, this ends up importing as a generic typealias. PrintAsObjC previously didn’t handle declarations involving these types correctly; it would fail an assertion in asserts compilers, and potentially print an incorrect compatibility header in non-asserts compilers. This PR makes it so that PrintAsObjC can now correctly use generic typealiases imported from Objective-C modules. It is, of course, still not possible to declare a generic typealias in Swift that will be printed into the Objective-C header. Fixes rdar://67256866. --- lib/PrintAsObjC/DeclAndTypePrinter.cpp | 23 ++++++++++++++++--- lib/PrintAsObjC/ModuleContentsWriter.cpp | 5 ++-- .../custom-modules/CompatibilityAlias.h | 2 ++ test/PrintAsObjC/classes.swift | 3 +++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 4653c9c1293c8..f2ff6c495431b 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -1572,12 +1572,16 @@ class DeclAndTypePrinter::Implementation } bool printImportedAlias(const TypeAliasDecl *alias, + ArrayRef genericArgs, Optional optionalKind) { if (!alias->hasClangNode()) return false; if (auto *clangTypeDecl = dyn_cast(alias->getClangDecl())) { + assert(!alias->isGeneric() + && "generic typealias backed by clang typedecl?"); + maybePrintTagKeyword(alias); os << getNameForObjC(alias); @@ -1585,12 +1589,19 @@ class DeclAndTypePrinter::Implementation printNullability(optionalKind); } else if (auto *clangObjCClass = dyn_cast(alias->getClangDecl())){ + assert(!alias->isGeneric() + && "generic typealias backed by clang interface?"); + os << clangObjCClass->getName() << " *"; printNullability(optionalKind); } else { auto *clangCompatAlias = cast(alias->getClangDecl()); - os << clangCompatAlias->getName() << " *"; + + os << clangCompatAlias->getName(); + if (!genericArgs.empty()) + printGenericArgs(genericArgs); + os << " *"; printNullability(optionalKind); } @@ -1600,10 +1611,12 @@ class DeclAndTypePrinter::Implementation void visitTypeAliasType(TypeAliasType *aliasTy, Optional optionalKind) { const TypeAliasDecl *alias = aliasTy->getDecl(); + auto genericArgs = aliasTy->getDirectGenericArgs(); + if (printIfKnownSimpleType(alias, optionalKind)) return; - if (printImportedAlias(alias, optionalKind)) + if (printImportedAlias(alias, genericArgs, optionalKind)) return; visitPart(aliasTy->getSinglyDesugaredType(), optionalKind); @@ -1737,8 +1750,12 @@ class DeclAndTypePrinter::Implementation } void printGenericArgs(BoundGenericType *BGT) { + printGenericArgs(BGT->getGenericArgs()); + } + + void printGenericArgs(ArrayRef genericArgs) { os << '<'; - interleave(BGT->getGenericArgs(), + interleave(genericArgs, [this](Type t) { print(t, None); }, [this] { os << ", "; }); os << '>'; diff --git a/lib/PrintAsObjC/ModuleContentsWriter.cpp b/lib/PrintAsObjC/ModuleContentsWriter.cpp index 135cabf70ea5d..b5b466c2210d0 100644 --- a/lib/PrintAsObjC/ModuleContentsWriter.cpp +++ b/lib/PrintAsObjC/ModuleContentsWriter.cpp @@ -57,7 +57,6 @@ class ReferencedTypeFinder : public TypeDeclFinder { Action visitTypeAliasType(TypeAliasType *aliasTy) override { if (aliasTy->getDecl()->hasClangNode() && !aliasTy->getDecl()->isCompatibilityAlias()) { - assert(!aliasTy->getDecl()->isGeneric()); Callback(*this, aliasTy->getDecl()); } else { Type(aliasTy->getSinglyDesugaredType()).walk(*this); @@ -319,8 +318,10 @@ class ModuleWriter { } else if (auto PD = dyn_cast(TD)) { forwardDeclare(PD); } else if (auto TAD = dyn_cast(TD)) { + bool imported = false; if (TAD->hasClangNode()) - (void)addImport(TD); + imported = addImport(TD); + assert((imported || !TAD->isGeneric()) && "referencing non-imported generic typealias?"); } else if (addImport(TD)) { return; } else if (auto ED = dyn_cast(TD)) { diff --git a/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h b/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h index 0d8ec65a05288..45e6515b4bf73 100644 --- a/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h +++ b/test/PrintAsObjC/Inputs/custom-modules/CompatibilityAlias.h @@ -1,5 +1,7 @@ // This file is meant to be included with modules turned off, compiled against // the fake clang-importer-sdk. #import +#import @compatibility_alias StringCheese NSString; +@compatibility_alias GymClass GenericClass; diff --git a/test/PrintAsObjC/classes.swift b/test/PrintAsObjC/classes.swift index 55b6b7edaccd5..69c2beae96e5a 100644 --- a/test/PrintAsObjC/classes.swift +++ b/test/PrintAsObjC/classes.swift @@ -820,6 +820,9 @@ public class NonObjCClass { } // CHECK-NEXT: - (StringCheese * _Nullable)foo SWIFT_WARN_UNUSED_RESULT; @objc func foo() -> StringCheese? { return nil } + // CHECK-NEXT: - (GymClass * _Nullable)foosball SWIFT_WARN_UNUSED_RESULT; + @objc func foosball() -> GymClass? { return nil } + // CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; } // CHECK-NEXT: @end From 2f7e0d496f14cc45c8972d129f0e0daf19f9bd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Tue, 18 Aug 2020 16:58:58 -0700 Subject: [PATCH 268/663] Revert "Revert "[Serialization] Serialize isUserAccessible on functions"" This reverts commit bf25a017013e4d3c87a9abbb7b8b067e1eb985b2. --- lib/Serialization/Deserialization.cpp | 3 +++ lib/Serialization/ModuleFormat.h | 1 + lib/Serialization/Serialization.cpp | 1 + .../complete_user_accessibility_helper.swift | 3 +++ test/IDE/complete_user_accessible.swift | 19 +++++++++++++++++++ 5 files changed, 27 insertions(+) create mode 100644 test/IDE/Inputs/complete_user_accessibility_helper.swift create mode 100644 test/IDE/complete_user_accessible.swift diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index f56c3cad967e2..b4ac5ac283285 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2995,6 +2995,7 @@ class DeclDeserializer { DeclID accessorStorageDeclID; bool overriddenAffectsABI, needsNewVTableEntry, isTransparent; DeclID opaqueReturnTypeID; + bool isUserAccessible; ArrayRef nameAndDependencyIDs; if (!isAccessor) { @@ -3012,6 +3013,7 @@ class DeclDeserializer { rawAccessLevel, needsNewVTableEntry, opaqueReturnTypeID, + isUserAccessible, nameAndDependencyIDs); } else { decls_block::AccessorLayout::readRecord(scratch, contextID, isImplicit, @@ -3192,6 +3194,7 @@ class DeclDeserializer { fn->setForcedStaticDispatch(hasForcedStaticDispatch); ctx.evaluator.cacheOutput(NeedsNewVTableEntryRequest{fn}, std::move(needsNewVTableEntry)); + fn->setUserAccessible(isUserAccessible); if (opaqueReturnTypeID) { ctx.evaluator.cacheOutput( diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 0c6bc3f61564e..3cbf7d7ba0c6f 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -1308,6 +1308,7 @@ namespace decls_block { AccessLevelField, // access level BCFixed<1>, // requires a new vtable slot DeclIDField, // opaque result type decl + BCFixed<1>, // isUserAccessible? BCArray // name components, // followed by TypeID dependencies // The record is trailed by: diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 4e099c13de728..20179b2876c19 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3437,6 +3437,7 @@ class Serializer::DeclSerializer : public DeclVisitor { rawAccessLevel, fn->needsNewVTableEntry(), S.addDeclRef(fn->getOpaqueResultTypeDecl()), + fn->isUserAccessible(), nameComponentsAndDependencies); writeGenericParams(fn->getGenericParams()); diff --git a/test/IDE/Inputs/complete_user_accessibility_helper.swift b/test/IDE/Inputs/complete_user_accessibility_helper.swift new file mode 100644 index 0000000000000..0ff5d6c417bf9 --- /dev/null +++ b/test/IDE/Inputs/complete_user_accessibility_helper.swift @@ -0,0 +1,3 @@ +public enum MyEnum { + case foo, bar +} diff --git a/test/IDE/complete_user_accessible.swift b/test/IDE/complete_user_accessible.swift new file mode 100644 index 0000000000000..551648d195f31 --- /dev/null +++ b/test/IDE/complete_user_accessible.swift @@ -0,0 +1,19 @@ +/// Check that serialized non user accessible functions are not autocompleted. +/// rdar://problem/53891642 +/// SR-7460 + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module %S/Inputs/complete_user_accessibility_helper.swift -module-name helper -emit-module-path %t/helper.swiftmodule +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=USER-ACCESS -I %t | %FileCheck %s -check-prefix=USER-ACCESS + +import helper + +{ + _ = MyEnum.#^USER-ACCESS^# +// USER-ACCESS: Begin completions +// USER-ACCESS-DAG: Keyword[self]/CurrNominal: self[#MyEnum.Type#]; name=self +// USER-ACCESS-DAG: Keyword/CurrNominal: Type[#MyEnum.Type#]; name=Type +// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: foo[#MyEnum#]; name=foo +// USER-ACCESS-DAG: Decl[EnumElement]/CurrNominal: bar[#MyEnum#]; name=bar +// USER-ACCESS-NOT: __derived_enum_equals +} From 256226d35e02c52a370b12a68f06e048a1e8335a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Thu, 20 Aug 2020 16:24:24 -0700 Subject: [PATCH 269/663] [Serialization] Fix isUserAccessible serialization on functions only --- lib/Serialization/Deserialization.cpp | 4 +++- lib/Serialization/ModuleFormat.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index b4ac5ac283285..0bb3cef17922d 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3194,7 +3194,6 @@ class DeclDeserializer { fn->setForcedStaticDispatch(hasForcedStaticDispatch); ctx.evaluator.cacheOutput(NeedsNewVTableEntryRequest{fn}, std::move(needsNewVTableEntry)); - fn->setUserAccessible(isUserAccessible); if (opaqueReturnTypeID) { ctx.evaluator.cacheOutput( @@ -3202,6 +3201,9 @@ class DeclDeserializer { cast(MF.getDecl(opaqueReturnTypeID))); } + if (!isAccessor) + fn->setUserAccessible(isUserAccessible); + return fn; } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 3cbf7d7ba0c6f..50a000ccb62ae 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 573; // @async on SILFunctionType +const uint16_t SWIFTMODULE_VERSION_MINOR = 574; // reapply isUserAccessible /// A standard hash seed used for all string hashes in a serialized module. /// From fd78da51372478b6734cc059a8626d033cde60b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Thu, 20 Aug 2020 12:04:10 -0700 Subject: [PATCH 270/663] [ModuleInterface] Don't print extensions to implementation-only imported types Extensions to implementation-only types are accepted at type-checking only if they don't define any public members. However if they declared a conformance to a public type they were also printed in the swiftinterface, making it unparsable because of an unknown type. Still accept such extensions but don't print them. rdar://problem/67516588 --- include/swift/AST/Module.h | 6 +++ lib/AST/ASTPrinter.cpp | 8 ++++ lib/AST/Module.cpp | 21 ++++++++++ test/ModuleInterface/empty-extension.swift | 49 ++++++++++++++++++++++ test/SPI/Inputs/ioi_helper.swift | 1 + test/SPI/private_swiftinterface.swift | 7 ++++ 6 files changed, 92 insertions(+) create mode 100644 test/ModuleInterface/empty-extension.swift create mode 100644 test/SPI/Inputs/ioi_helper.swift diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 0a1ff8f42ba2a..5a9334a41b8f0 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -685,6 +685,12 @@ class ModuleDecl : public DeclContext, public TypeDecl { void getImportedModulesForLookup(SmallVectorImpl &imports) const; + /// Has \p module been imported via an '@_implementationOnly' import + /// instead of another kind of import? + /// + /// This assumes that \p module was imported. + bool isImportedImplementationOnly(const ModuleDecl *module) const; + /// Uniques the items in \p imports, ignoring the source locations of the /// access paths. /// diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index ed03d9a2c35c0..2eb113c7a67e5 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -169,6 +169,14 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, if (auto *ED = dyn_cast(D)) { if (!shouldPrint(ED->getExtendedNominal(), options)) return false; + + // Skip extensions to implementation-only imported types. + auto localModule = ED->getParentModule(); + auto nominalModule = ED->getExtendedNominal()->getParentModule(); + if (localModule != nominalModule && + localModule->isImportedImplementationOnly(nominalModule)) + return false; + for (const Requirement &req : ED->getGenericRequirements()) { if (!isPublicOrUsableFromInline(req.getFirstType())) return false; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 7ffb167d69800..3399d77f3aa7c 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -1994,6 +1994,27 @@ bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const { return !imports.isImportedBy(module, getParentModule()); } +bool ModuleDecl::isImportedImplementationOnly(const ModuleDecl *module) const { + auto &imports = getASTContext().getImportCache(); + + // Look through non-implementation-only imports to see if module is imported + // in some other way. Otherwise we assume it's implementation-only imported. + ModuleDecl::ImportFilter filter = { + ModuleDecl::ImportFilterKind::Public, + ModuleDecl::ImportFilterKind::Private, + ModuleDecl::ImportFilterKind::SPIAccessControl, + ModuleDecl::ImportFilterKind::ShadowedBySeparateOverlay}; + SmallVector results; + getImportedModules(results, filter); + + for (auto &desc : results) { + if (imports.isImportedBy(module, desc.importedModule)) + return false; + } + + return true; +} + void SourceFile::lookupImportedSPIGroups( const ModuleDecl *importedModule, llvm::SmallSetVector &spiGroups) const { diff --git a/test/ModuleInterface/empty-extension.swift b/test/ModuleInterface/empty-extension.swift new file mode 100644 index 0000000000000..65323afcbcf86 --- /dev/null +++ b/test/ModuleInterface/empty-extension.swift @@ -0,0 +1,49 @@ +// Test that we don't print extensions to implementation-only imported types. + +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -emit-module %s -DIOI_LIB -module-name IOILib -emit-module-path %t/IOILib.swiftmodule +// RUN: %target-swift-frontend -emit-module %s -DEXPORTED_LIB -module-name IndirectLib -emit-module-path %t/IndirectLib.swiftmodule -I %t +// RUN: %target-swift-frontend -emit-module %s -DLIB -module-name Lib -emit-module-path %t/Lib.swiftmodule -I %t + +// RUN: %target-swift-frontend-typecheck -emit-module-interface-path %t/out.swiftinterface %s -I %t -swift-version 5 -enable-library-evolution +// RUN: %FileCheck %s < %t/out.swiftinterface + +#if IOI_LIB + +public struct IOIImportedType { + public func foo() {} +} + +#elseif EXPORTED_LIB + +public struct ExportedType { + public func foo() {} +} + +#elseif LIB + +@_exported import IndirectLib + +public struct NormalImportedType { + public func foo() {} +} + +#else // Client + +import Lib +@_implementationOnly import IOILib + +public protocol PublicProto { + func foo() +} +extension IOIImportedType : PublicProto {} +// CHECK-NOT: IOIImportedType + +extension NormalImportedType : PublicProto {} +// CHECK: extension NormalImportedType + +extension ExportedType : PublicProto {} +// CHECK: extension ExportedType + +#endif diff --git a/test/SPI/Inputs/ioi_helper.swift b/test/SPI/Inputs/ioi_helper.swift new file mode 100644 index 0000000000000..f885a21d07f60 --- /dev/null +++ b/test/SPI/Inputs/ioi_helper.swift @@ -0,0 +1 @@ +public struct IOIPublicStruct {} diff --git a/test/SPI/private_swiftinterface.swift b/test/SPI/private_swiftinterface.swift index 6af2d40bc51f2..9473a265af173 100644 --- a/test/SPI/private_swiftinterface.swift +++ b/test/SPI/private_swiftinterface.swift @@ -3,6 +3,7 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module %S/Inputs/spi_helper.swift -module-name SPIHelper -emit-module-path %t/SPIHelper.swiftmodule -swift-version 5 -enable-library-evolution -emit-module-interface-path %t/SPIHelper.swiftinterface -emit-private-module-interface-path %t/SPIHelper.private.swiftinterface +// RUN: %target-swift-frontend -emit-module %S/Inputs/ioi_helper.swift -module-name IOIHelper -emit-module-path %t/IOIHelper.swiftmodule -swift-version 5 -enable-library-evolution -emit-module-interface-path %t/IOIHelper.swiftinterface -emit-private-module-interface-path %t/IOIHelper.private.swiftinterface /// Make sure that the public swiftinterface of spi_helper doesn't leak SPI. // RUN: %FileCheck -check-prefix=CHECK-HELPER %s < %t/SPIHelper.swiftinterface @@ -25,6 +26,7 @@ // CHECK-PUBLIC: import SPIHelper // CHECK-PRIVATE: @_spi(OtherSPI) @_spi(HelperSPI) import SPIHelper +@_implementationOnly import IOIHelper public func foo() {} // CHECK-PUBLIC: foo() // CHECK-PRIVATE: foo() @@ -155,6 +157,11 @@ extension PublicType: SPIProto2 where T: SPIProto2 {} // CHECK-PRIVATE: extension PublicType : {{.*}}.SPIProto2 where T : {{.*}}.SPIProto2 // CHECK-PUBLIC-NOT: _ConstraintThatIsNotPartOfTheAPIOfThisLibrary +public protocol LocalPublicProto {} +extension IOIPublicStruct : LocalPublicProto {} +// CHECK-PRIVATE-NOT: IOIPublicStruct +// CHECK-PUBLIC-NOT: IOIPublicStruct + // The dummy conformance should be only in the private swiftinterface for // SPI extensions. @_spi(LocalSPI) From 3d61c211c1fab2af1d0cd946af4e92041a0ae396 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Thu, 20 Aug 2020 19:12:50 -0700 Subject: [PATCH 271/663] [AutoDiff] Revert obsolete SIL undef hack. (#33571) Previously, JVP/VJP generation used a "return undef" hack when differential/pullback values did not match the expected return type. This was relevant before differentiation supported "loadable types with address-only tangent types", which was diagnosed. Now that support for the above exists, "return undef" should be removed and replaced with an assertion. --- lib/SILOptimizer/Differentiation/JVPCloner.cpp | 11 +++++------ lib/SILOptimizer/Differentiation/VJPCloner.cpp | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index b6df19215ba4d..27625aceb0b38 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -704,9 +704,11 @@ class JVPCloner::Implementation final getModule(), jvpSubstMap, TypeExpansionContext::minimal()); differentialType = differentialType.subst(getModule(), jvpSubstMap); auto differentialFnType = differentialType.castTo(); - auto differentialSubstType = differentialPartialApply->getType().castTo(); + + // If necessary, convert the differential value to the returned differential + // function type. SILValue differentialValue; if (differentialSubstType == differentialFnType) { differentialValue = differentialPartialApply; @@ -717,11 +719,8 @@ class JVPCloner::Implementation final loc, differentialPartialApply, differentialType, /*withoutActuallyEscaping*/ false); } else { - // When `diag::autodiff_loadable_value_addressonly_tangent_unsupported` - // applies, the return type may be ABI-incomaptible with the type of the - // partially applied differential. In these cases, produce an undef and - // rely on other code to emit a diagnostic. - differentialValue = SILUndef::get(differentialType, *jvp); + llvm::report_fatal_error("Differential value type is not ABI-compatible " + "with the returned differential type"); } // Return a tuple of the original result and differential. diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index c3037cdb76693..dc0d915148e20 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -201,9 +201,11 @@ class VJPCloner::Implementation final getModule(), vjpSubstMap, TypeExpansionContext::minimal()); pullbackType = pullbackType.subst(getModule(), vjpSubstMap); auto pullbackFnType = pullbackType.castTo(); - auto pullbackSubstType = pullbackPartialApply->getType().castTo(); + + // If necessary, convert the pullback value to the returned pullback + // function type. SILValue pullbackValue; if (pullbackSubstType == pullbackFnType) { pullbackValue = pullbackPartialApply; @@ -213,11 +215,8 @@ class VJPCloner::Implementation final builder.createConvertFunction(loc, pullbackPartialApply, pullbackType, /*withoutActuallyEscaping*/ false); } else { - // When `diag::autodiff_loadable_value_addressonly_tangent_unsupported` - // applies, the return type may be ABI-incomaptible with the type of the - // partially applied pullback. In these cases, produce an undef and rely - // on other code to emit a diagnostic. - pullbackValue = SILUndef::get(pullbackType, *vjp); + llvm::report_fatal_error("Pullback value type is not ABI-compatible " + "with the returned pullback type"); } // Return a tuple of the original result and pullback. From ec29edd5b07be02049fb4ee9da63fae54a2eab30 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 21 Aug 2020 05:10:46 +0300 Subject: [PATCH 272/663] Sema: Pass substitution options to swift::checkTypeWitness ...to propagate tentative type witnesses when validating a solution to associated type inference --- lib/Sema/TypeCheckProtocol.cpp | 25 ++++++---- lib/Sema/TypeCheckProtocol.h | 3 +- lib/Sema/TypeCheckProtocolInference.cpp | 8 ++-- .../protocol/conforms/associated_type.swift | 47 ++++++++++--------- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 83f8444d64122..ec752d6c50c92 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3788,9 +3788,10 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault( # pragma mark Type witness resolution -CheckTypeWitnessResult swift::checkTypeWitness(Type type, - AssociatedTypeDecl *assocType, - NormalProtocolConformance *Conf) { +CheckTypeWitnessResult +swift::checkTypeWitness(Type type, AssociatedTypeDecl *assocType, + const NormalProtocolConformance *Conf, + SubstOptions options) { if (type->hasError()) return ErrorType::get(assocType->getASTContext()); @@ -3804,13 +3805,19 @@ CheckTypeWitnessResult swift::checkTypeWitness(Type type, : type; if (auto superclass = genericSig->getSuperclassBound(depTy)) { - // If the superclass has a type parameter, substitute in known type - // witnesses. if (superclass->hasTypeParameter()) { - const auto subMap = SubstitutionMap::getProtocolSubstitutions( - proto, Conf->getType(), ProtocolConformanceRef(Conf)); - - superclass = superclass.subst(subMap); + // Replace type parameters with other known or tentative type witnesses. + superclass = superclass.subst( + [&](SubstitutableType *type) { + if (type->isEqual(proto->getSelfInterfaceType())) + return Conf->getType(); + + return Type(); + }, + LookUpConformanceInModule(dc->getParentModule()), options); + + if (superclass->hasTypeParameter()) + superclass = dc->mapTypeIntoContext(superclass); } if (!superclass->isExactSuperclassOf(contextType)) return superclass; diff --git a/lib/Sema/TypeCheckProtocol.h b/lib/Sema/TypeCheckProtocol.h index badf16810d0b7..d51341300ac48 100644 --- a/lib/Sema/TypeCheckProtocol.h +++ b/lib/Sema/TypeCheckProtocol.h @@ -96,7 +96,8 @@ class CheckTypeWitnessResult { /// \returns an empty result on success, or a description of the error. CheckTypeWitnessResult checkTypeWitness(Type type, AssociatedTypeDecl *assocType, - NormalProtocolConformance *Conf); + const NormalProtocolConformance *Conf, + SubstOptions options = None); /// Describes the means of inferring an abstract type witness. enum class AbstractTypeWitnessKind : uint8_t { diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index a4b6621ecdd3a..23a6957b930ef 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -1172,6 +1172,7 @@ AssociatedTypeDecl *AssociatedTypeInference::completeSolution( // Check each abstract type witness we computed against the generic // requirements on the corresponding associated type. + const auto substOptions = getSubstOptionsWithCurrentTypeWitnesses(); for (const auto &witness : abstractTypeWitnesses) { Type type = witness.getType(); if (type->hasTypeParameter()) { @@ -1184,8 +1185,7 @@ AssociatedTypeDecl *AssociatedTypeInference::completeSolution( return Type(); }, - LookUpConformanceInModule(dc->getParentModule()), - getSubstOptionsWithCurrentTypeWitnesses()); + LookUpConformanceInModule(dc->getParentModule()), substOptions); // If the substitution produced an error, we're done. if (type->hasError()) @@ -1194,8 +1194,8 @@ AssociatedTypeDecl *AssociatedTypeInference::completeSolution( type = dc->mapTypeIntoContext(type); } - if (const auto &failed = - checkTypeWitness(type, witness.getAssocType(), conformance)) { + if (const auto &failed = checkTypeWitness(type, witness.getAssocType(), + conformance, substOptions)) { // We failed to satisfy a requirement. If this is a default type // witness failure and we haven't seen one already, write it down. if (witness.getKind() == AbstractTypeWitnessKind::Default && diff --git a/test/decl/protocol/conforms/associated_type.swift b/test/decl/protocol/conforms/associated_type.swift index f299611655ef8..805624c6f36a6 100644 --- a/test/decl/protocol/conforms/associated_type.swift +++ b/test/decl/protocol/conforms/associated_type.swift @@ -94,27 +94,8 @@ struct SR_12707_Conform_P2: SR_12707_P2 { typealias A = Never } -// Default type witness -protocol SR_12707_P3 { - associatedtype A - associatedtype B: SR_12707_C<(A, Self)> = SR_12707_C<(A, Self)> -} -struct SR_12707_Conform_P3: SR_12707_P3 { - typealias A = Never -} - -// FIXME: Type witness resolution success is order-dependent. -protocol SR_12707_FIXME_P1 { - associatedtype A -} -protocol SR_12707_FIXME_P2: SR_12707_FIXME_P1 { - associatedtype B: SR_12707_C<(A, Self)> = SR_12707_C<(A, Self)> // expected-note {{default type 'associated_type.SR_12707_C<(associated_type.SR_12707_FIXME_Conform_P2.A, associated_type.SR_12707_FIXME_Conform_P2)>' (aka 'SR_12707_C<(Never, SR_12707_FIXME_Conform_P2)>') for associated type 'B' (from protocol 'SR_12707_FIXME_P2') does not inherit from 'associated_type.SR_12707_C<(associated_type.SR_12707_FIXME_Conform_P2.A, associated_type.SR_12707_FIXME_Conform_P2)>'}} -} -struct SR_12707_FIXME_Conform_P2: SR_12707_FIXME_P2 { // expected-error {{type 'SR_12707_FIXME_Conform_P2' does not conform to protocol 'SR_12707_FIXME_P2'}} - typealias A = Never -} - -// FIXME: Type witness resolution success is order-dependent. +// FIXME: resolveTypeWitnessViaLookup must not happen independently in the +// general case. protocol SR_12707_FIXME_P3 { associatedtype A: SR_12707_C // expected-note {{protocol requires nested type 'A'; do you want to add it?}} associatedtype B @@ -123,3 +104,27 @@ struct SR_12707_FIXME_Conform_P3: SR_12707_FIXME_P3 { // expected-error {{type ' typealias A = SR_12707_C // expected-note {{possibly intended match 'SR_12707_FIXME_Conform_P3.A' (aka 'SR_12707_C') does not inherit from 'SR_12707_C'}} typealias B = Never } + +// FIXME: Associated type inference via value witnesses should consider +// tentative witnesses when checking a candidate. +protocol SR_12707_FIXME_P4 { + associatedtype X = Never + + associatedtype A: SR_12707_C // expected-note {{unable to infer associated type 'A' for protocol 'SR_12707_FIXME_P4'}} + func foo(arg: A) +} +struct SR_12707_FIXME_Conform_P4: SR_12707_FIXME_P4 { // expected-error {{type 'SR_12707_FIXME_Conform_P4' does not conform to protocol 'SR_12707_FIXME_P4'}} + func foo(arg: SR_12707_C) {} // expected-note {{candidate would match and infer 'A' = 'SR_12707_C' if 'SR_12707_C' inherited from 'SR_12707_C'}} +} + +// Abstract type witnesses. +protocol SR_12707_P5a { + associatedtype X = Never + + associatedtype A: SR_12707_C + associatedtype B: SR_12707_C +} +protocol SR_12707_P5b: SR_12707_P5a where B == SR_12707_C { + associatedtype C: SR_12707_C = SR_12707_C +} +struct SR_12707_Conform_P5>: SR_12707_P5b {} From 13cf37a2ee4dc3d340f5ae79ce52d9919089ca55 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 20 Aug 2020 21:36:06 -0700 Subject: [PATCH 273/663] Patch A Regression in Lookup for CodingKeys Codable's magic previously relied on the subject of every qualified lookup in an unqualified lookup stack to force the synthesis of this member. This allowed users to reference CodingKeys transitively through a non-primary input without qualification. As part of the requestification of name lookup, this synthesis was moved out of the normal qualified lookup path and into the Type Checker's semantic lookup entrypoints in order to prevent wild cycles caused by protocol conformance resolution. In the process, we forget to restore the synthesis check at this entrypoint. To patch up the source break this caused, we need to walk the context stack again and force synthesis. Unfortunately, we're stuck with a hack like this until we bring Codable's implementation back out of the realm of magic once more. A future implementation of synthesizeSemanticMembersIfNeeded should aim to just craft the AST for CodingKeys, but not actually run any of the semantic checks until we check the conformance to CodingKey. rdar://65088901, SR-13137 --- lib/Sema/TypeCheckNameLookup.cpp | 20 ++++++++++++++++++- .../Inputs/struct_codable_simple_multi1.swift | 8 ++++++++ .../Inputs/struct_codable_simple_multi2.swift | 8 ++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 46eb592abd1e2..1cddaedd4f562 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -220,8 +220,26 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) { LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclNameRef name, SourceLoc loc, NameLookupOptions options) { - auto ulOptions = convertToUnqualifiedLookupOptions(options); auto &ctx = dc->getASTContext(); + // HACK: Qualified lookup cannot be allowed to synthesize CodingKeys because + // it would lead to a number of egregious cycles through + // QualifiedLookupRequest when we resolve the protocol conformance. Codable's + // magic has pushed its way so deeply into the compiler, we have to + // pessimistically force every nominal context above this one to synthesize + // it in the event the user needs it from e.g. a non-primary input. + // We can undo this if Codable's semantic content is divorced from its + // syntactic content - so we synthesize just enough to allow lookups to + // succeed, but don't force protocol conformances while we're doing it. + if (name.getBaseIdentifier() == ctx.Id_CodingKeys) { + for (auto typeCtx = dc->getInnermostTypeContext(); typeCtx != nullptr; + typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { + if (auto *nominal = typeCtx->getSelfNominalTypeDecl()) { + nominal->synthesizeSemanticMembersIfNeeded(name.getFullName()); + } + } + } + + auto ulOptions = convertToUnqualifiedLookupOptions(options); auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, ulOptions); auto lookup = evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {}); diff --git a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift index 7d72e19fe049d..2bd193260a0f2 100644 --- a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift +++ b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift @@ -21,3 +21,11 @@ struct SimpleStruct : Codable { let _ = SimpleStruct.CodingKeys.z // expected-error {{type 'SimpleStruct.CodingKeys' has no member 'z'}} } } + +// SR-13137 Ensure unqualified lookup installs CodingKeys regardless of the +// order of primaries. +struct A: Codable { + var property: String + static let propertyName = CodingKeys.property.stringValue +} + diff --git a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift index e1c762b8d296a..96310709d71a4 100644 --- a/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift +++ b/test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift @@ -8,3 +8,11 @@ func foo() { // struct. let _ = SimpleStruct.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}} } + +struct B { + static let propertyName = A.propertyName + + struct Nest { + static let propertyName = A.propertyName + } +} From f3045ff9c2c80cfe5422803a60cc42e3315b0c91 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 20 Aug 2020 23:17:52 -0700 Subject: [PATCH 274/663] DependenciesScanner: teach batch scanning mode to configure scanner using specified additional arguments To help solving rdar://67079780, this change allows swift-driver to configure scanner using additional arguments passed down via the batch input JSON file for each module under scanning. --- include/swift/AST/DiagnosticsCommon.def | 3 ++ lib/FrontendTool/FrontendTool.cpp | 8 ++-- lib/FrontendTool/ScanDependencies.cpp | 45 ++++++++++++++++--- lib/FrontendTool/ScanDependencies.h | 5 ++- test/ScanDependencies/Inputs/CHeaders/H.h | 5 +++ test/ScanDependencies/Inputs/CHeaders/I.h | 1 + .../Inputs/CHeaders/module.modulemap | 10 +++++ .../batch_module_scan_arguments.swift | 24 ++++++++++ 8 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 test/ScanDependencies/Inputs/CHeaders/H.h create mode 100644 test/ScanDependencies/Inputs/CHeaders/I.h create mode 100644 test/ScanDependencies/batch_module_scan_arguments.swift diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index cdeef09e3058e..f4c39ce036d06 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -185,5 +185,8 @@ WARNING(cross_imported_by_both_modules, none, ERROR(scanner_find_cycle, none, "dependency scanner detected dependency cycle: '%0'", (StringRef)) +ERROR(scanner_arguments_invalid, none, + "dependencies scanner cannot be configured with arguments: '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index cfeddc5af96a4..2a2fc8ed642a8 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1751,7 +1751,8 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { /// \param Instance Will be reset after performIRGeneration when the verifier /// mode is NoVerify and there were no errors. /// \returns true on error -static bool performCompile(CompilerInstance &Instance, +static bool performCompile(CompilerInvocation &Invok, + CompilerInstance &Instance, ArrayRef Args, int &ReturnValue, FrontendObserver *observer) { @@ -1839,7 +1840,8 @@ static bool performCompile(CompilerInstance &Instance, if (batchScanInput.empty()) return finishPipeline(scanDependencies(Instance)); else - return finishPipeline(batchScanModuleDependencies(Instance, + return finishPipeline(batchScanModuleDependencies(Invok, + Instance, batchScanInput)); } @@ -2652,7 +2654,7 @@ int swift::performFrontend(ArrayRef Args, } int ReturnValue = 0; - bool HadError = performCompile(*Instance, Args, ReturnValue, observer); + bool HadError = performCompile(Invocation, *Instance, Args, ReturnValue, observer); if (verifierEnabled) { DiagnosticEngine &diags = Instance->getDiags(); diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index 524a5de2213e6..fb0cd4b47a0bc 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -31,6 +31,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/YAMLTraits.h" @@ -626,7 +627,6 @@ static bool diagnoseCycle(CompilerInstance &instance, static bool scanModuleDependencies(CompilerInstance &instance, StringRef moduleName, - StringRef arguments, bool isClang, StringRef outputPath) { ASTContext &ctx = instance.getASTContext(); @@ -685,14 +685,14 @@ static bool scanModuleDependencies(CompilerInstance &instance, bool swift::scanClangDependencies(CompilerInstance &instance) { return scanModuleDependencies(instance, instance.getMainModule()->getNameStr(), - StringRef(), /*isClang*/true, instance.getInvocation().getFrontendOptions() .InputsAndOutputs.getSingleOutputFilename()); } -bool swift::batchScanModuleDependencies(CompilerInstance &instance, - llvm::StringRef batchInputFile) { +bool swift::batchScanModuleDependencies(CompilerInvocation &invok, + CompilerInstance &instance, + llvm::StringRef batchInputFile) { (void)instance.getMainModule(); llvm::BumpPtrAllocator alloc; llvm::StringSaver saver(alloc); @@ -700,10 +700,43 @@ bool swift::batchScanModuleDependencies(CompilerInstance &instance, batchInputFile, saver); if (!results.hasValue()) return true; + auto &diags = instance.getDiags(); + ForwardingDiagnosticConsumer FDC(diags); + // Keep track of all compiler instances we have created. + llvm::StringMap> subInstanceMap; for (auto &entry: *results) { - if (scanModuleDependencies(instance, entry.moduleName, entry.arguments, - !entry.isSwift, entry.outputPath)) + CompilerInstance *pInstance = nullptr; + if (entry.arguments.empty()) { + // Use the compiler's instance if no arguments are specified. + pInstance = &instance; + } else if (subInstanceMap.count(entry.arguments)) { + // Use the previously created instance if we've seen the arguments before. + pInstance = subInstanceMap[entry.arguments].get(); + } else { + // Create a new instance by the arguments and save it in the map. + pInstance = subInstanceMap.insert({entry.arguments, + std::make_unique()}).first->getValue().get(); + SmallVector args; + llvm::cl::TokenizeGNUCommandLine(entry.arguments, saver, args); + CompilerInvocation subInvok = invok; + pInstance->addDiagnosticConsumer(&FDC); + if (subInvok.parseArgs(args, diags)) { + instance.getDiags().diagnose(SourceLoc(), diag::scanner_arguments_invalid, + entry.arguments); + return true; + } + if (pInstance->setup(subInvok)) { + instance.getDiags().diagnose(SourceLoc(), diag::scanner_arguments_invalid, + entry.arguments); + return true; + } + } + assert(pInstance); + // Scan using the chosen compiler instance. + if (scanModuleDependencies(*pInstance, entry.moduleName, !entry.isSwift, + entry.outputPath)) { return true; + } } return false; } diff --git a/lib/FrontendTool/ScanDependencies.h b/lib/FrontendTool/ScanDependencies.h index d4e0cf1a2c544..4604496ba66dc 100644 --- a/lib/FrontendTool/ScanDependencies.h +++ b/lib/FrontendTool/ScanDependencies.h @@ -17,10 +17,13 @@ namespace swift { +class CompilerInvocation; class CompilerInstance; /// Batch scan the dependencies for modules specified in \c batchInputFile. -bool batchScanModuleDependencies(CompilerInstance &instance, llvm::StringRef batchInputFile); +bool batchScanModuleDependencies(CompilerInvocation &invok, + CompilerInstance &instance, + llvm::StringRef batchInputFile); /// Scans the dependencies of the main module of \c instance. bool scanDependencies(CompilerInstance &instance); diff --git a/test/ScanDependencies/Inputs/CHeaders/H.h b/test/ScanDependencies/Inputs/CHeaders/H.h new file mode 100644 index 0000000000000..9c4b66d8f0e84 --- /dev/null +++ b/test/ScanDependencies/Inputs/CHeaders/H.h @@ -0,0 +1,5 @@ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000 +#include "I.h" +#endif + +void funcH(void); diff --git a/test/ScanDependencies/Inputs/CHeaders/I.h b/test/ScanDependencies/Inputs/CHeaders/I.h new file mode 100644 index 0000000000000..d9ddc05cc65b4 --- /dev/null +++ b/test/ScanDependencies/Inputs/CHeaders/I.h @@ -0,0 +1 @@ +void funcI(void); diff --git a/test/ScanDependencies/Inputs/CHeaders/module.modulemap b/test/ScanDependencies/Inputs/CHeaders/module.modulemap index dbd29ce9d9739..481266591c912 100644 --- a/test/ScanDependencies/Inputs/CHeaders/module.modulemap +++ b/test/ScanDependencies/Inputs/CHeaders/module.modulemap @@ -27,3 +27,13 @@ module G { header "G.h" export * } + +module H { + header "H.h" + export * +} + +module I { + header "I.h" + export * +} diff --git a/test/ScanDependencies/batch_module_scan_arguments.swift b/test/ScanDependencies/batch_module_scan_arguments.swift new file mode 100644 index 0000000000000..65f2320766ec7 --- /dev/null +++ b/test/ScanDependencies/batch_module_scan_arguments.swift @@ -0,0 +1,24 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: %empty-directory(%t/outputs) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: echo "[{" > %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"H\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/H.10.9.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}," >> %/t/inputs/input.json +// RUN: echo "{" >> %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"H\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx11.0\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/H.11.0.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}]" >> %/t/inputs/input.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix=CHECK-TEN < %t/outputs/H.10.9.pcm.json +// RUN: %FileCheck %s -check-prefix=CHECK-ELEVEN < %t/outputs/H.11.0.pcm.json + +// CHECK-TEN: "clang": "I" +// CHECK-ELEVEN-NOT: "clang": "I" From bfe74f53cdcea0788395dd00d5907121236d94af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Fri, 21 Aug 2020 12:40:33 -0700 Subject: [PATCH 275/663] [ModuleInterface] Only skip extensions without public members Additionnal restrictions to still print some extensions to implementation-only imported types if marked SPI. --- lib/AST/ASTPrinter.cpp | 16 +++++++++++++--- ...experimental_spi_imports_swiftinterface.swift | 9 ++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 2eb113c7a67e5..de48919eab2b3 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -170,12 +170,22 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, if (!shouldPrint(ED->getExtendedNominal(), options)) return false; - // Skip extensions to implementation-only imported types. + // Skip extensions to implementation-only imported types that have + // no public members. auto localModule = ED->getParentModule(); auto nominalModule = ED->getExtendedNominal()->getParentModule(); if (localModule != nominalModule && - localModule->isImportedImplementationOnly(nominalModule)) - return false; + localModule->isImportedImplementationOnly(nominalModule)) { + + bool shouldPrintMembers = llvm::any_of( + ED->getMembers(), + [&](const Decl *member) -> bool { + return shouldPrint(member, options); + }); + + if (!shouldPrintMembers) + return false; + } for (const Requirement &req : ED->getGenericRequirements()) { if (!isPublicOrUsableFromInline(req.getFirstType())) diff --git a/test/SPI/experimental_spi_imports_swiftinterface.swift b/test/SPI/experimental_spi_imports_swiftinterface.swift index 76a50f21796da..35d715424d387 100644 --- a/test/SPI/experimental_spi_imports_swiftinterface.swift +++ b/test/SPI/experimental_spi_imports_swiftinterface.swift @@ -4,7 +4,7 @@ /// Generate 3 empty modules. // RUN: touch %t/empty.swift -// RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name ExperimentalImported -emit-module-path %t/ExperimentalImported.swiftmodule -swift-version 5 -enable-library-evolution +// RUN: %target-swift-frontend -emit-module %S/Inputs/ioi_helper.swift -module-name ExperimentalImported -emit-module-path %t/ExperimentalImported.swiftmodule -swift-version 5 -enable-library-evolution // RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name IOIImported -emit-module-path %t/IOIImported.swiftmodule -swift-version 5 -enable-library-evolution // RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name SPIImported -emit-module-path %t/SPIImported.swiftmodule -swift-version 5 -enable-library-evolution @@ -24,3 +24,10 @@ @_spi(dummy) import SPIImported // CHECK-PUBLIC: {{^}}import SPIImported // CHECK-PRIVATE: @_spi{{.*}} import SPIImported + +@_spi(X) +extension IOIPublicStruct { + public func foo() {} +} +// CHECK-PUBLIC-NOT: IOIPublicStruct +// CHECK-PRIVATE: @_spi{{.*}} extension IOIPublicStruct From 94bf392e0e8f9e747311913e4de49f9ac055df83 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 21 Aug 2020 15:08:22 -0700 Subject: [PATCH 276/663] [CSGen] Abort constraint generation on error only if closure participates in type-check If reference collection discovered at least `ErrorExpr` in the body of a closure, let's fail constraint generation only if it's a single-statement closure, decision about multi-statement closures should be delayed until body is opened. This helps code completion because `ErrorExpr` could belong to a statement unrelated to a completion, so it wouldn't affect its correctness in any way. --- lib/Sema/CSGen.cpp | 9 ++++++++- test/expr/closure/closures.swift | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0891e23c6474c..0be9a16ca3d28 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2784,10 +2784,17 @@ namespace { return { true, expr }; } } collectVarRefs(CS); + closure->walk(collectVarRefs); - if (collectVarRefs.hasErrorExprs) + // If walker discovered error expressions, let's fail constraint + // genreation only if closure is going to participate + // in the type-check. This allows us to delay validation of + // multi-statement closures until body is opened. + if (shouldTypeCheckInEnclosingExpression(closure) && + collectVarRefs.hasErrorExprs) { return Type(); + } auto inferredType = inferClosureType(closure); if (!inferredType || inferredType->hasError()) diff --git a/test/expr/closure/closures.swift b/test/expr/closure/closures.swift index 37c704b492714..f2b5eb5a0cf9f 100644 --- a/test/expr/closure/closures.swift +++ b/test/expr/closure/closures.swift @@ -141,6 +141,7 @@ func anonymousClosureArgsInClosureWithArgs() { var a5 = { (_: [Int], w: [Int]) in f($0.count) // expected-error {{anonymous closure arguments cannot be used inside a closure that has explicit arguments}} f($1.count) // expected-error {{anonymous closure arguments cannot be used inside a closure that has explicit arguments; did you mean 'w'?}} {{7-9=w}} + // expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'String'}} } } From 83b2ebe8f1ea15ec5c69f98f0d4f5b8792ce22e3 Mon Sep 17 00:00:00 2001 From: Alex Efremov Date: Sat, 22 Aug 2020 02:57:39 +0200 Subject: [PATCH 277/663] [AutoDiff] Support forward mode differentiation of functions with `inout` parameters (#33584) Adds forward mode support for `apply` instruction with `inout` arguments. Example of supported code: ``` func add(_ x: inout Float, _ y: inout Float) -> Float { var result = x result += y return result } print(differential(at: 1, 1, in: add)(1, 1)) // prints "2" ``` --- .../Differentiation/JVPCloner.cpp | 67 ++++---- .../FloatingPointDifferentiation.swift.gyb | 6 +- .../forward_mode_diagnostics.swift | 63 +++---- .../validation-test/forward_mode_inout.swift | 161 ++++++++++++++++++ 4 files changed, 220 insertions(+), 77 deletions(-) create mode 100644 test/AutoDiff/validation-test/forward_mode_inout.swift diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index 27625aceb0b38..f2e1d04aea635 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -455,18 +455,6 @@ class JVPCloner::Implementation final return; } - // Diagnose functions with active inout arguments. - // TODO(TF-129): Support `inout` argument differentiation. - for (auto inoutArg : ai->getInoutArguments()) { - if (activityInfo.isActive(inoutArg, getIndices())) { - context.emitNondifferentiabilityError( - ai, invoker, - diag::autodiff_cannot_differentiate_through_inout_arguments); - errorOccurred = true; - return; - } - } - auto loc = ai->getLoc(); auto &builder = getBuilder(); auto origCallee = getOpValue(ai->getCallee()); @@ -1241,6 +1229,10 @@ class JVPCloner::Implementation final SmallVector differentialAllResults; collectAllActualResultsInTypeOrder( differentialCall, differentialDirectResults, differentialAllResults); + for (auto inoutArg : ai->getInoutArguments()) + origAllResults.push_back(inoutArg); + for (auto inoutArg : differentialCall->getInoutArguments()) + differentialAllResults.push_back(inoutArg); assert(applyIndices.results->getNumIndices() == differentialAllResults.size()); @@ -1484,11 +1476,14 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto origIndResults = original->getIndirectResults(); auto diffIndResults = differential.getIndirectResults(); #ifndef NDEBUG - unsigned numInoutParameters = llvm::count_if( - original->getLoweredFunctionType()->getParameters(), - [](SILParameterInfo paramInfo) { return paramInfo.isIndirectInOut(); }); - assert(origIndResults.size() + numInoutParameters == diffIndResults.size()); + unsigned numNonWrtInoutParameters = llvm::count_if( + range(original->getLoweredFunctionType()->getNumParameters()), + [&] (unsigned i) { + auto ¶mInfo = original->getLoweredFunctionType()->getParameters()[i]; + return paramInfo.isIndirectInOut() && !getIndices().parameters->contains(i); + }); #endif + assert(origIndResults.size() + numNonWrtInoutParameters == diffIndResults.size()); for (auto &origBB : *original) for (auto i : indices(origIndResults)) setTangentBuffer(&origBB, origIndResults[i], diffIndResults[i]); @@ -1521,23 +1516,10 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto origParams = origTy->getParameters(); auto indices = witness->getSILAutoDiffIndices(); - // Add differential results. - Optional inoutDiffParam = None; - for (auto origParam : origTy->getParameters()) { - if (!origParam.isIndirectInOut()) - continue; - inoutDiffParam = origParam; - } - - if (inoutDiffParam) { - dfResults.push_back( - SILResultInfo(inoutDiffParam->getInterfaceType() - ->getAutoDiffTangentSpace(lookupConformance) - ->getType() - ->getCanonicalType(witnessCanGenSig), - ResultConvention::Indirect)); - } else { - for (auto resultIndex : indices.results->getIndices()) { + + for (auto resultIndex : indices.results->getIndices()) { + if (resultIndex < origTy->getNumResults()) { + // Handle formal original result. auto origResult = origTy->getResults()[resultIndex]; origResult = origResult.getWithInterfaceType( origResult.getInterfaceType()->getCanonicalType(witnessCanGenSig)); @@ -1548,6 +1530,25 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { ->getCanonicalType(witnessCanGenSig), origResult.getConvention())); } + else { + // Handle original `inout` parameter. + auto inoutParamIndex = resultIndex - origTy->getNumResults(); + auto inoutParamIt = std::next( + origTy->getIndirectMutatingParameters().begin(), inoutParamIndex); + auto paramIndex = + std::distance(origTy->getParameters().begin(), &*inoutParamIt); + // If the original `inout` parameter is a differentiability parameter, then + // it already has a corresponding differential parameter. Skip adding a + // corresponding differential result. + if (indices.parameters->contains(paramIndex)) + continue; + auto inoutParam = origTy->getParameters()[paramIndex]; + auto paramTan = inoutParam.getInterfaceType()->getAutoDiffTangentSpace( + lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + dfResults.push_back( + {paramTan->getCanonicalType(), ResultConvention::Indirect}); + } } // Add differential parameters for the requested wrt parameters. diff --git a/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb b/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb index 8de2cd5ca2a5b..f2ff2fcbff530 100644 --- a/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb +++ b/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb @@ -205,8 +205,9 @@ extension ${Self} { static func _jvpMultiplyAssign(_ lhs: inout ${Self}, _ rhs: ${Self}) -> ( value: Void, differential: (inout ${Self}, ${Self}) -> Void ) { + let oldLhs = lhs lhs *= rhs - return ((), { $0 *= $1 }) + return ((), { $0 = $0 * rhs + oldLhs * $1 }) } ${Availability(bits)} @@ -251,8 +252,9 @@ extension ${Self} { static func _jvpDivideAssign(_ lhs: inout ${Self}, _ rhs: ${Self}) -> ( value: Void, differential: (inout ${Self}, ${Self}) -> Void ) { + let oldLhs = lhs lhs /= rhs - return ((), { $0 /= $1 }) + return ((), { $0 = ($0 * rhs - oldLhs * $1) / (rhs * rhs) }) } } diff --git a/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift b/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift index f028db4baca4f..ad21c18467142 100644 --- a/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/forward_mode_diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -enable-experimental-forward-mode-differentiation -emit-sil -verify %s +// RUN: %target-swift-frontend -emit-sil -enable-experimental-forward-mode-differentiation -verify %s // Test forward-mode differentiation transform diagnostics. @@ -46,8 +46,6 @@ func nonVariedResult(_ x: Float) -> Float { // Multiple results //===----------------------------------------------------------------------===// -// TODO(TF-983): Support differentiation of multiple results. -/* func multipleResults(_ x: Float) -> (Float, Float) { return (x, x) } @@ -56,28 +54,21 @@ func usesMultipleResults(_ x: Float) -> Float { let tuple = multipleResults(x) return tuple.0 + tuple.1 } -*/ //===----------------------------------------------------------------------===// // `inout` parameter differentiation //===----------------------------------------------------------------------===// -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func activeInoutParamNonactiveInitialResult(_ x: Float) -> Float { var result: Float = 1 - // expected-note @+1 {{cannot differentiate through 'inout' arguments}} result += x return result } -// expected-error @+1 {{function is not differentiable}} @differentiable -// expected-note @+1 {{when differentiating this function definition}} func activeInoutParamTuple(_ x: Float) -> Float { var tuple = (x, x) - // expected-note @+1 {{cannot differentiate through 'inout' arguments}} tuple.0 *= x return x * tuple.0 } @@ -94,49 +85,37 @@ func activeInoutParamControlFlow(_ array: [Float]) -> Float { return result } -struct Mut: Differentiable {} -extension Mut { - @differentiable(wrt: x) - mutating func mutatingMethod(_ x: Mut) {} -} - // FIXME(TF-984): Forward-mode crash due to unset tangent buffer. /* -@differentiable(wrt: x) -func nonActiveInoutParam(_ nonactive: inout Mut, _ x: Mut) -> Mut { - return nonactive.mutatingMethod(x) +struct X: Differentiable { + var x : Float + + @differentiable(wrt: y) + mutating func mutate(_ y: X) { self.x = y.x } } -*/ -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* -@differentiable(wrt: x) -func activeInoutParamMutatingMethod(_ x: Mut) -> Mut { - var result = x - result = result.mutatingMethod(result) - return result +@differentiable +func activeMutatingMethod(_ x: Float) -> Float { + let x1 = X.init(x: x) + var x2 = X.init(x: 0) + x2.mutate(x1) + return x1.x } */ -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* -@differentiable(wrt: x) -func activeInoutParamMutatingMethodVar(_ nonactive: inout Mut, _ x: Mut) -> Mut { - var result = nonactive - result = result.mutatingMethod(x) - return result + +struct Mut: Differentiable {} +extension Mut { + @differentiable(wrt: x) + mutating func mutatingMethod(_ x: Mut) {} } -*/ -// FIXME(TF-984): Forward-mode crash due to unset tangent buffer. -/* @differentiable(wrt: x) -func activeInoutParamMutatingMethodTuple(_ nonactive: inout Mut, _ x: Mut) -> Mut { - var result = (nonactive, x) - let result2 = result.0.mutatingMethod(result.0) - return result2 +func activeInoutParamMutatingMethod(_ x: Mut) -> Mut { + var result = x + result.mutatingMethod(result) + return result } -*/ //===----------------------------------------------------------------------===// // Subset parameter differentiation thunks diff --git a/test/AutoDiff/validation-test/forward_mode_inout.swift b/test/AutoDiff/validation-test/forward_mode_inout.swift new file mode 100644 index 0000000000000..42ed40a89c6ca --- /dev/null +++ b/test/AutoDiff/validation-test/forward_mode_inout.swift @@ -0,0 +1,161 @@ +// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-forward-mode-differentiation) +// REQUIRES: executable_test + +import StdlibUnittest +import DifferentiationUnittest + +var ForwardModeInoutTests = TestSuite("ForwardModeInoutDifferentiation") + +//===----------------------------------------------------------------------===// +// Inout tests. +//===----------------------------------------------------------------------===// + +import DifferentiationUnittest +import StdlibUnittest + +ForwardModeInoutTests.test("Float.+=") { + func mutatingAddWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result += y + return result + } + expectEqual(20, differential(at: 4, 5, in: mutatingAddWrapper)(10, 10)) +} + +ForwardModeInoutTests.test("Float.-=") { + func mutatingSubtractWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result -= y + return result + } + expectEqual(0, differential(at: 4, 5, in: mutatingSubtractWrapper)(10, 10)) + expectEqual(10, differential(at: 4, 5, in: mutatingSubtractWrapper)(20, 10)) +} + +ForwardModeInoutTests.test("Float.*=") { + func mutatingMultiplyWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result *= y + return result + } + expectEqual(22, differential(at: 4, 5, in: mutatingMultiplyWrapper)(2, 3)) +} + +ForwardModeInoutTests.test("Float./=") { + func mutatingDivideWrapper(_ x: Float, _ y: Float) -> Float { + var result: Float = x + result /= y + return result + } + expectEqual(-1, differential(at: 2, 3, in: mutatingDivideWrapper)(3, 9)) +} + +// Simplest possible `inout` parameter differentiation. +ForwardModeInoutTests.test("InoutIdentity") { + // Semantically, an empty function with an `inout` parameter is an identity + // function. + func inoutIdentity(_ x: inout Float) {} + + func identity(_ x: Float) -> Float { + var result = x + inoutIdentity(&result) + return result + } + expectEqual(1, derivative(at: 10, in: identity)) + expectEqual(10, differential(at: 10, in: identity)(10)) + + func inoutIdentityGeneric(_ x: inout T) {} + + func identityGeneric(_ x: T) -> T { + var result: T = x + inoutIdentityGeneric(&result) + return result + } + expectEqual(1, derivative(at: 10.0, in: identityGeneric)) + expectEqual(10, differential(at: 10.0, in: identityGeneric)(10)) +} + +ForwardModeInoutTests.test("MultipleInoutParams") { + func swap(_ x: inout T, _ y: inout T) { + let z = x + x = y + y = z + } + + func first(_ x: T, _ y: T) -> T { + var p1 = x + var p2 = y + swap(&p1, &p2) + return p2 + } + expectEqual(1, differential(at: 1, 1, in: first)(1, 2)) + + func second(_ x: T, _ y: T) -> T { + var p1 = x + var p2 = y + swap(&p1, &p2) + return p1 + } + expectEqual(2, differential(at: 1, 1, in: second)(1, 2)) +} + +ForwardModeInoutTests.test("StructMutatingMethod") { + struct Mut: Differentiable { + var x: Float + + mutating func add(_ y: Float) { + self.x += y + } + + mutating func addMut(_ m: Mut) { + self.x += m.x + } + } + + func identity(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + mut.add(y) + return mut.x + } + expectEqual(1, derivative(at: 1, in: identity)) + + func identity2(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + let mut2 = Mut(x: y) + mut.addMut(mut2) + return mut.x + } + expectEqual(1, derivative(at: 1, in: identity2)) + + func double(_ y: Float) -> Float { + var mut = Mut(x: y) + mut.add(y) + return mut.x + } + expectEqual(2, derivative(at: 1, in: double)) + + func double2(_ y: Float) -> Float { + var mut = Mut(x: y) + let mut2 = Mut(x: y) + mut.addMut(mut2) + return mut.x + } + expectEqual(2, derivative(at: 1, in: double2)) + + func square(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + mut.add(y * y) + return mut.x + } + expectEqual(6, derivative(at: 3, in: square)) + + func square2(_ y: Float) -> Float { + var mut = Mut(x: 0.0) + let mut2 = Mut(x: y * y) + mut.addMut(mut2) + return mut.x + } + expectEqual(6, derivative(at: 3, in: square2)) +} + +runAllTests() From 6a7b38d7efaba1a36c63a6bcb3bf55a49b139676 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Sat, 22 Aug 2020 01:58:44 +0100 Subject: [PATCH 278/663] [SILGenPattern] Silence redundant unreachable enum case warning (#33336) --- lib/SILGen/SILGenPattern.cpp | 23 +++++++++++++++++++---- test/SILGen/unreachable_code.swift | 17 +++++++++++++---- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp index b7ee169fc9faf..a63b0bd512862 100644 --- a/lib/SILGen/SILGenPattern.cpp +++ b/lib/SILGen/SILGenPattern.cpp @@ -1038,20 +1038,35 @@ void PatternMatchEmission::emitDispatch(ClauseMatrix &clauses, ArgArray args, SGF.eraseBasicBlock(contBB); return; } - + // Otherwise, if there is no fallthrough, then the next row is - // unreachable: emit a dead code diagnostic. + // unreachable: emit a dead code diagnostic if: + // 1) It's for a 'default' case (since Space Engine already handles + // unreachable enum case patterns) or it's for a enum case which + // has expression patterns since redundancy checking for such + // patterns isn't sufficiently done by the Space Engine. + // 2) It's for a case statement in a do-catch. if (!clauses[firstRow].hasFallthroughTo()) { SourceLoc Loc; bool isDefault = false; + bool isParentDoCatch = false; + bool caseHasExprPattern = false; if (auto *S = clauses[firstRow].getClientData()) { Loc = S->getStartLoc(); - if (auto *CS = dyn_cast(S)) + if (auto *CS = dyn_cast(S)) { + caseHasExprPattern = llvm::any_of( + CS->getCaseLabelItems(), [&](const CaseLabelItem item) { + return item.getPattern()->getKind() == PatternKind::Expr; + }); + isParentDoCatch = CS->getParentKind() == CaseParentKind::DoCatch; isDefault = CS->isDefault(); + } } else { Loc = clauses[firstRow].getCasePattern()->getStartLoc(); } - SGF.SGM.diagnose(Loc, diag::unreachable_case, isDefault); + if (isParentDoCatch || isDefault || caseHasExprPattern) { + SGF.SGM.diagnose(Loc, diag::unreachable_case, isDefault); + } } } } diff --git a/test/SILGen/unreachable_code.swift b/test/SILGen/unreachable_code.swift index 79c3fb0837f44..799a27a49eefc 100644 --- a/test/SILGen/unreachable_code.swift +++ b/test/SILGen/unreachable_code.swift @@ -67,8 +67,7 @@ func testUnreachableCase1(a : Tree) { case let Leaf: _ = Leaf return - case .Branch(_): // expected-warning {{case will never be executed}} - // expected-warning@-1 {{case is already handled by previous patterns; consider removing it}} + case .Branch(_): // expected-warning {{case is already handled by previous patterns; consider removing it}} return } } @@ -87,8 +86,7 @@ func testUnreachableCase3(a : Tree) { switch a { case _: break - case .Branch(_): // expected-warning {{case will never be executed}} - // expected-warning@-1 {{case is already handled by previous patterns; consider removing it}} + case .Branch(_): // expected-warning {{case is already handled by previous patterns; consider removing it}} return } } @@ -137,3 +135,14 @@ func sr6141() { return; bar?.append("x") // expected-warning{{code after 'return' will never be executed}} } + +func testUnreachableCatchClause() { + enum ErrorEnum: Error { case someError } + do { + throw ErrorEnum.someError + } catch let error { + print(error) + } catch ErrorEnum.someError { // expected-warning {{case will never be executed}} + print("some error") + } +} From 0bd8b140db55fe8cd59d91f8359f2fbe7593d0b2 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Fri, 21 Aug 2020 19:44:12 -0700 Subject: [PATCH 279/663] [AST] Fix declaration bitfields. (#33567) Fix total bit count for Decl and AbstractFunctionDecl bitfields. --- include/swift/AST/Decl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 92d70f2af9083..c21cac7948679 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -283,7 +283,7 @@ class alignas(1 << DeclAlignInBits) Decl { protected: union { uint64_t OpaqueBits; - SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1, + SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1, Kind : bitmax(NumDeclKindBits,8), /// Whether this declaration is invalid. @@ -385,7 +385,7 @@ class alignas(1 << DeclAlignInBits) Decl { SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2, StaticSpelling : 2 ); - SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1, /// \see AbstractFunctionDecl::BodyKind BodyKind : 3, From 0034cabe7bdf986cbd90e11278a0ec9a28ddc10a Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Fri, 21 Aug 2020 22:53:50 -0700 Subject: [PATCH 280/663] [AST] Fix missing include in Decl.cpp --- lib/AST/Decl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4fdb7199e4ba3..f35ff446cc486 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -59,6 +59,7 @@ #include "swift/Demangling/ManglingMacros.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/Module.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" From af35936589a5ae77f071fdc7ba413883154b09c6 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Sat, 22 Aug 2020 10:51:04 -0400 Subject: [PATCH 281/663] [Runtime] Fix a race condition in ConcurrentReadableHashMap with concurrent reads and clears. --- include/swift/Runtime/Concurrent.h | 34 +++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 17339f6503533..099b8a3fa560f 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -830,9 +830,37 @@ template struct ConcurrentReadableHashMap { /// Take a snapshot of the current state of the hash map. Snapshot snapshot() { incrementReaders(); - auto *indices = Indices.load(SWIFT_MEMORY_ORDER_CONSUME); - auto elementCount = ElementCount.load(std::memory_order_acquire); - auto *elements = Elements.load(std::memory_order_acquire); + + // Carefully loading the indices, element count, and elements pointer in + // order ensures a consistent view of the table with respect to concurrent + // inserts. However, this is not sufficient to avoid an inconsistent view + // with respect to concurrent clears. The danger scenario is: + // + // 1. Read indices and elementCount from a table with N entries. + // 2. Another thread clears the table. + // 3. Another thread inserts M entries, where M < N. + // 4. The reader thread reads elements. + // 5. The reader thread performs a find. The key's hash leads us to an index + // I, where > M. + // 6. The reader thread reads from element I, which is off the end of the + // elements array. + // + // To avoid this, read the elements pointer twice, at the beginning and end. + // If the values are not the same then there may have been a clear in the + // middle, so we retry. This will have false positives: a new element + // pointer can just mean a concurrent insert that triggered a resize of the + // elements array. This is harmless aside from a small performance hit, and + // should not happen often. + IndexStorage *indices; + size_t elementCount; + ElemTy *elements; + ElemTy *elements2; + do { + elements = Elements.load(std::memory_order_acquire); + indices = Indices.load(SWIFT_MEMORY_ORDER_CONSUME); + elementCount = ElementCount.load(std::memory_order_acquire); + elements2 = Elements.load(std::memory_order_acquire); + } while (elements != elements2); return Snapshot(this, indices, elements, elementCount); } From 7aac6817d47011c86e1486af6753cc57882ce131 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 18 Aug 2020 20:21:04 -0700 Subject: [PATCH 282/663] [opt-remark] Handle inline locations correctly. Specifically, now we properly identify the SILLocation for the final inlined call site of a Source Location and put the remark there instead of in the callee. --- include/swift/SIL/SILDebugScope.h | 22 +++++++++++++ lib/SIL/Utils/OptimizationRemark.cpp | 32 ++++++++++++------- .../Transforms/OptRemarkGenerator.cpp | 24 ++++++++------ test/SILOptimizer/opt-remark-generator.swift | 26 +++++++++++++++ 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/include/swift/SIL/SILDebugScope.h b/include/swift/SIL/SILDebugScope.h index ce9ad200ac77e..0349ed6dbffc8 100644 --- a/include/swift/SIL/SILDebugScope.h +++ b/include/swift/SIL/SILDebugScope.h @@ -66,6 +66,28 @@ class SILDebugScope : public SILAllocated { /// into. SILFunction *getParentFunction() const; + /// If this is a debug scope associated with an inlined call site, return the + /// SILLocation associated with the call site resulting from the final + /// inlining. + /// + /// This allows one to emit diagnostics based off of inlined code's final + /// location in the function that was inlined into. + SILLocation getOutermostInlineLocation() const { + if (!InlinedCallSite) + return SILLocation::invalid(); + + auto *scope = this; + do { + scope = scope->InlinedCallSite; + } while (scope->InlinedCallSite); + + SILLocation callSite = scope->Loc; + if (callSite.isNull() || !callSite.isASTNode()) + return SILLocation::invalid(); + + return callSite; + } + void print(SourceManager &SM, llvm::raw_ostream &OS = llvm::errs(), unsigned Indent = 0) const; diff --git a/lib/SIL/Utils/OptimizationRemark.cpp b/lib/SIL/Utils/OptimizationRemark.cpp index 00da367598e31..6a778f0266c16 100644 --- a/lib/SIL/Utils/OptimizationRemark.cpp +++ b/lib/SIL/Utils/OptimizationRemark.cpp @@ -152,6 +152,8 @@ static SourceLoc inferOptRemarkSearchForwards(SILInstruction &i) { for (auto &inst : llvm::make_range(std::next(i.getIterator()), i.getParent()->end())) { auto newLoc = inst.getLoc().getSourceLoc(); + if (auto inlinedLoc = inst.getDebugScope()->getOutermostInlineLocation()) + newLoc = inlinedLoc.getSourceLoc(); if (newLoc.isValid()) return newLoc; } @@ -167,7 +169,9 @@ static SourceLoc inferOptRemarkSearchBackwards(SILInstruction &i) { for (auto &inst : llvm::make_range(std::next(i.getReverseIterator()), i.getParent()->rend())) { auto loc = inst.getLoc(); - if (!bool(loc)) + if (auto inlinedLoc = inst.getDebugScope()->getOutermostInlineLocation()) + loc = inlinedLoc; + if (!loc.getSourceLoc().isValid()) continue; auto range = loc.getSourceRange(); @@ -180,12 +184,16 @@ static SourceLoc inferOptRemarkSearchBackwards(SILInstruction &i) { SourceLoc swift::OptRemark::inferOptRemarkSourceLoc( SILInstruction &i, SourceLocInferenceBehavior inferBehavior) { - auto loc = i.getLoc().getSourceLoc(); - - // Do a quick check if we already have a valid loc. In such a case, just - // return. Otherwise, we try to infer using one of our heuristics below. - if (loc.isValid()) - return loc; + // Do a quick check if we already have a valid loc and it isnt an inline + // loc. In such a case, just return. Otherwise, we try to infer using one of + // our heuristics below. + auto loc = i.getLoc(); + if (loc.getSourceLoc().isValid()) { + // Before we do anything, if we do not have an inlined call site, just + // return our loc. + if (!i.getDebugScope() || !i.getDebugScope()->InlinedCallSite) + return loc.getSourceLoc(); + } // Otherwise, try to handle the individual behavior cases, returning loc at // the end of each case (its invalid, so it will get ignored). If loc is not @@ -193,18 +201,18 @@ SourceLoc swift::OptRemark::inferOptRemarkSourceLoc( // was missed. switch (inferBehavior) { case SourceLocInferenceBehavior::None: - return loc; + return SourceLoc(); case SourceLocInferenceBehavior::ForwardScanOnly: { SourceLoc newLoc = inferOptRemarkSearchForwards(i); if (newLoc.isValid()) return newLoc; - return loc; + return SourceLoc(); } case SourceLocInferenceBehavior::BackwardScanOnly: { SourceLoc newLoc = inferOptRemarkSearchBackwards(i); if (newLoc.isValid()) return newLoc; - return loc; + return SourceLoc(); } case SourceLocInferenceBehavior::ForwardThenBackward: { SourceLoc newLoc = inferOptRemarkSearchForwards(i); @@ -213,7 +221,7 @@ SourceLoc swift::OptRemark::inferOptRemarkSourceLoc( newLoc = inferOptRemarkSearchBackwards(i); if (newLoc.isValid()) return newLoc; - return loc; + return SourceLoc(); } case SourceLocInferenceBehavior::BackwardThenForward: { SourceLoc newLoc = inferOptRemarkSearchBackwards(i); @@ -222,7 +230,7 @@ SourceLoc swift::OptRemark::inferOptRemarkSourceLoc( newLoc = inferOptRemarkSearchForwards(i); if (newLoc.isValid()) return newLoc; - return loc; + return SourceLoc(); } } diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index c6cb5c7e6a5e5..4de1f0ddf7e0d 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -42,7 +42,7 @@ static llvm::cl::opt ForceVisitImplicitAutogeneratedFunctions( llvm::cl::init(false)); //===----------------------------------------------------------------------===// -// Utility +// Value To Decl Inferrer //===----------------------------------------------------------------------===// namespace { @@ -176,15 +176,21 @@ bool ValueToDeclInferrer::infer( continue; if (auto *dvi = dyn_cast(use->getUser())) { - if (auto *decl = dvi->getDecl()) { - std::string msg; - { - llvm::raw_string_ostream stream(msg); - printNote(stream, decl); + // Check if our debug_value has a decl and was not inlined into the + // current function. + if (auto *scope = dvi->getDebugScope()) { + if (!scope->InlinedCallSite) { + if (auto *decl = dvi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + foundDeclFromUse = true; + } } - resultingInferredDecls.push_back( - Argument({keyKind, "InferredValue"}, std::move(msg), decl)); - foundDeclFromUse = true; } } } diff --git a/test/SILOptimizer/opt-remark-generator.swift b/test/SILOptimizer/opt-remark-generator.swift index c354552f173af..9b06fc17a76c6 100644 --- a/test/SILOptimizer/opt-remark-generator.swift +++ b/test/SILOptimizer/opt-remark-generator.swift @@ -231,3 +231,29 @@ func inoutKlassQuestionCastArgument2(x: inout Klass?) -> SubKlass? { return x as? SubKlass // expected-remark {{retain of type 'Klass'}} // expected-note @-2 {{of 'x.some'}} } + +// We should have 1x rr remark here on calleeX for storing it into the array to +// print. Release is from the array. We don't pattern match it due to the actual +// underlying Array type name changing under the hood in between platforms. +@inline(__always) +func alwaysInlineCallee(_ calleeX: Klass) { + print(calleeX) // expected-remark @:5 {{retain of type 'Klass'}} + // expected-note @-2:27 {{of 'calleeX'}} + // expected-remark @-2:18 {{release of type}} +} + +// We should have 3x rr remarks here on callerX and none on calleeX. All of the +// releases are for the temporary array that we pass into print. +// +// TODO: Should we print out as notes the whole inlined call stack? +func alwaysInlineCaller(_ callerX: Klass) { + alwaysInlineCallee(callerX) // expected-remark @:5 {{retain of type 'Klass'}} + // expected-note @-2:27 {{of 'callerX'}} + // expected-remark @-2:31 {{release of type}} + print(callerX) // expected-remark @:5 {{retain of type 'Klass'}} + // expected-note @-5:27 {{of 'callerX'}} + // expected-remark @-2:18 {{release of type}} + alwaysInlineCallee(callerX) // expected-remark @:5 {{retain of type 'Klass'}} + // expected-note @-8:27 {{of 'callerX'}} + // expected-remark @-2:31 {{release of type}} +} From 8337f961d8c24bdbe333f38d826b414598c70ce0 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Sat, 22 Aug 2020 16:32:05 -0700 Subject: [PATCH 283/663] [Package] When building a toolchain, don't copy the Resource directory. Should dramatically improve the size of the snapshost produced, as we don't have stdlib et similia included twice. Also, it helps when producing fat binaries, as we don't have to implement any mechanism for sandwiching all the slices together. --- utils/build-presets.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 70e13bd38481b..397b2661498cb 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1234,6 +1234,11 @@ verbose-build build-ninja build-swift-stdlib-unittest-extra +# When producing a package, don't copy the Swift Resource/ directory. +# This is mainly a space optimization. +extra-cmake-options= + -DLLDB_FRAMEWORK_COPY_SWIFT_RESOURCES=0 + install-llvm install-swift install-lldb From 611d4b830722426bde0354605f3c2c7cbb73f3e7 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sat, 22 Aug 2020 18:48:56 -0700 Subject: [PATCH 284/663] [gardening] PlaygroundSupport is a build-script product now... remove dead-code remnants. Just deleting dead code. --- utils/build-script-impl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 6e471f191c386..16bf04f3efaf9 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1231,9 +1231,6 @@ function build_directory_bin() { ;; libicu) ;; - playgroundsupport) - echo "${root}/${PLAYGROUNDSUPPORT_BUILD_TYPE}/bin" - ;; *) echo "error: unknown product: ${product}" exit 1 @@ -1352,9 +1349,6 @@ function cmake_config_opt() { ;; libicu) ;; - playgroundsupport) - echo "--config ${PLAYGROUNDSUPPORT_BUILD_TYPE}" - ;; *) echo "error: unknown product: ${product}" exit 1 From ac64ad6f853373b0e863f7bdd9f35c94b0159be5 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 27 Jul 2020 13:20:39 -0700 Subject: [PATCH 285/663] [opt-remark] Add remarks for alloc_box, alloc_ref, alloc_stack Specifically, we can identify rr on alloc_stack, alloc_ref, alloc_box and also can emit a remark if ref,box result in heap allocations. --- .../Transforms/OptRemarkGenerator.cpp | 131 ++++++++++++++++-- ...enerator-force-emit-implicit-autogen.swift | 3 +- .../opt-remark-generator-semantics.swift | 52 ++++--- .../opt-remark-generator-yaml.swift | 35 ++++- test/SILOptimizer/opt-remark-generator.swift | 129 ++++++++++------- 5 files changed, 262 insertions(+), 88 deletions(-) diff --git a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp index 4de1f0ddf7e0d..987c36ed0cc36 100644 --- a/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp +++ b/lib/SILOptimizer/Transforms/OptRemarkGenerator.cpp @@ -71,7 +71,10 @@ struct ValueToDeclInferrer { void ValueToDeclInferrer::printNote(llvm::raw_string_ostream &stream, const ValueDecl *decl) { + assert(decl && + "We assume for now that this is always called with a non-null decl"); stream << "of '" << decl->getBaseName(); + for (auto &pair : accessPath) { auto baseType = pair.first; auto &proj = pair.second; @@ -133,6 +136,12 @@ static SingleValueInstruction *isSupportedProjection(Projection p, SILValue v) { llvm_unreachable("Covered switch is not covered?!"); } +static bool hasNonInlinedDebugScope(SILInstruction *i) { + if (auto *scope = i->getDebugScope()) + return !scope->InlinedCallSite; + return false; +} + bool ValueToDeclInferrer::infer( ArgumentKeyKind keyKind, SILValue value, SmallVectorImpl &resultingInferredDecls) { @@ -167,6 +176,46 @@ bool ValueToDeclInferrer::infer( return true; } + if (auto *ari = dyn_cast(value)) { + if (auto *decl = ari->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + return true; + } + } + + if (auto *abi = dyn_cast(value)) { + if (auto *decl = abi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); + } + + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + return true; + } + } + + if (auto *asi = dyn_cast(value)) { + if (auto *decl = asi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); + } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + return true; + } + } + // Then visit our users and see if we can find a debug_value that provides // us with a decl we can use to construct an argument. bool foundDeclFromUse = false; @@ -178,18 +227,16 @@ bool ValueToDeclInferrer::infer( if (auto *dvi = dyn_cast(use->getUser())) { // Check if our debug_value has a decl and was not inlined into the // current function. - if (auto *scope = dvi->getDebugScope()) { - if (!scope->InlinedCallSite) { - if (auto *decl = dvi->getDecl()) { - std::string msg; - { - llvm::raw_string_ostream stream(msg); - printNote(stream, decl); - } - resultingInferredDecls.push_back( - Argument({keyKind, "InferredValue"}, std::move(msg), decl)); - foundDeclFromUse = true; + if (hasNonInlinedDebugScope(dvi)) { + if (auto *decl = dvi->getDecl()) { + std::string msg; + { + llvm::raw_string_ostream stream(msg); + printNote(stream, decl); } + resultingInferredDecls.push_back( + Argument({keyKind, "InferredValue"}, std::move(msg), decl)); + foundDeclFromUse = true; } } } @@ -216,6 +263,8 @@ bool ValueToDeclInferrer::infer( } } + // TODO: We could emit at this point a msg for temporary allocations. + // If we reached this point, we finished falling through the loop and return // true. return true; @@ -245,6 +294,8 @@ struct OptRemarkGeneratorInstructionVisitor void visitStrongReleaseInst(StrongReleaseInst *sri); void visitRetainValueInst(RetainValueInst *rvi); void visitReleaseValueInst(ReleaseValueInst *rvi); + void visitAllocRefInst(AllocRefInst *ari); + void visitAllocBoxInst(AllocBoxInst *abi); void visitSILInstruction(SILInstruction *) {} }; @@ -333,6 +384,64 @@ void OptRemarkGeneratorInstructionVisitor::visitReleaseValueInst( }); } +void OptRemarkGeneratorInstructionVisitor::visitAllocRefInst( + AllocRefInst *ari) { + if (ari->canAllocOnStack()) { + return ORE.emit([&]() { + using namespace OptRemark; + SmallVector inferredArgs; + bool foundArgs = + valueToDeclInferrer.infer(ArgumentKeyKind::Note, ari, inferredArgs); + (void)foundArgs; + auto resultRemark = + RemarkPassed("memory", *ari, + SourceLocInferenceBehavior::ForwardScanOnly) + << "stack allocated ref of type '" << NV("ValueType", ari->getType()) + << "'"; + for (auto &arg : inferredArgs) + resultRemark << arg; + return resultRemark; + }); + } + + return ORE.emit([&]() { + using namespace OptRemark; + SmallVector inferredArgs; + bool foundArgs = + valueToDeclInferrer.infer(ArgumentKeyKind::Note, ari, inferredArgs); + (void)foundArgs; + + auto resultRemark = + RemarkMissed("memory", *ari, + SourceLocInferenceBehavior::ForwardScanOnly) + << "heap allocated ref of type '" << NV("ValueType", ari->getType()) + << "'"; + for (auto &arg : inferredArgs) + resultRemark << arg; + return resultRemark; + }); +} + +void OptRemarkGeneratorInstructionVisitor::visitAllocBoxInst( + AllocBoxInst *abi) { + return ORE.emit([&]() { + using namespace OptRemark; + SmallVector inferredArgs; + bool foundArgs = + valueToDeclInferrer.infer(ArgumentKeyKind::Note, abi, inferredArgs); + (void)foundArgs; + + auto resultRemark = + RemarkMissed("memory", *abi, + SourceLocInferenceBehavior::ForwardScanOnly) + << "heap allocated box of type '" << NV("ValueType", abi->getType()) + << "'"; + for (auto &arg : inferredArgs) + resultRemark << arg; + return resultRemark; + }); +} + //===----------------------------------------------------------------------===// // Top Level Entrypoint //===----------------------------------------------------------------------===// diff --git a/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift b/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift index 550a53e0dc120..9c49cd002cf51 100644 --- a/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift +++ b/test/SILOptimizer/opt-remark-generator-force-emit-implicit-autogen.swift @@ -1,6 +1,7 @@ // RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify -Xllvm -optremarkgen-visit-implicit-autogen-funcs=1 -class Klass {} +// From the constructor. +class Klass {} // expected-remark {{heap allocated ref of type 'Klass'}} struct KlassPair { var lhs: Klass // expected-remark {{retain of type 'Klass'}} diff --git a/test/SILOptimizer/opt-remark-generator-semantics.swift b/test/SILOptimizer/opt-remark-generator-semantics.swift index 513d7d3ef7cb3..ab39837098cb2 100644 --- a/test/SILOptimizer/opt-remark-generator-semantics.swift +++ b/test/SILOptimizer/opt-remark-generator-semantics.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-sil %s -verify -Osize +// RUN: %target-swift-frontend -emit-sil %s -verify -Osize -o /dev/null -module-name main // // NOTE: We only emit opt-remarks with -Osize,-O today! -O does drop way more // stuff though, so we test with -Osize. @@ -7,29 +7,41 @@ public class Klass {} public var mySingleton = Klass() +@inline(never) +func getGlobal() -> Klass { + return mySingleton +} + +@inline(never) +func useKlass(_ k: Klass) {} + @_semantics("optremark") @inline(never) -public func forceOptRemark() -> Klass { - return mySingleton // expected-remark {{retain}} - // expected-note @-6 {{of 'mySingleton'}} +public func forceOptRemark() { + let x = getGlobal() + useKlass(x) // expected-remark {{release of type 'Klass'}} + // expected-note @-2 {{of 'x'}} } @_semantics("optremark.sil-opt-remark-gen") @inline(never) -public func forceOptRemark2() -> Klass { - return mySingleton // expected-remark {{retain}} - // expected-note @-13 {{of 'mySingleton'}} +public func forceOptRemark2() { + let x = getGlobal() + useKlass(x) // expected-remark {{release of type 'Klass'}} + // expected-note @-2 {{of 'x'}} } @_semantics("optremark.fail") @inline(never) -public func failMatch() -> Klass { - return mySingleton +public func failMatch() { + let x = getGlobal() + useKlass(x) } @_semantics("optremark") public func allocateInlineCallee() -> Klass { return Klass() // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + // expected-remark @-1 {{heap allocated ref of type 'Klass'}} } @_semantics("optremark.sil-inliner") @@ -45,29 +57,31 @@ public func allocateInlineCallee3() -> Klass { @_semantics("optremark.sil-inliner") @_semantics("optremark.sil-opt-remark-gen") public func mix1() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} - // expected-remark @-1:5 {{retain}} - // expected-note @-42:12 {{of 'mySingleton'}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + // expected-remark @-1:16 {{heap allocated ref of type 'Klass'}} } @_semantics("optremark.sil-inliner") public func mix2() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} } @_semantics("optremark.sil-opt-remark-gen") public func mix3() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark @:5 {{retain}} - // expected-note @-53:12 {{of 'mySingleton'}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{heap allocated ref of type 'Klass'}} } @_semantics("optremark") public func mix4() -> (Klass, Klass) { - return (mySingleton, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} - // expected-remark @-1:5 {{retain}} - // expected-note @-60:12 {{of 'mySingleton'}} + let x = getGlobal() + return (x, Klass()) // expected-remark {{Pure call. Always profitable to inline "main.Klass.__allocating_init()"}} + // expected-remark @-1 {{heap allocated ref of type 'Klass'}} } public func mix5() -> (Klass, Klass) { - return (mySingleton, Klass()) + let x = getGlobal() + return (x, Klass()) } diff --git a/test/SILOptimizer/opt-remark-generator-yaml.swift b/test/SILOptimizer/opt-remark-generator-yaml.swift index 3dcd9fd051f5c..13a9301f1546d 100644 --- a/test/SILOptimizer/opt-remark-generator-yaml.swift +++ b/test/SILOptimizer/opt-remark-generator-yaml.swift @@ -9,7 +9,18 @@ public class Klass {} -public var global = Klass() +// CHECK: --- !Missed +// CHECK-NEXT: Pass: sil-opt-remark-gen +// CHECK-NEXT: Name: sil.memory +// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift', +// CHECK-NEXT: Line: [[# @LINE + 7 ]], Column: 21 } +// CHECK-NEXT: Function: main +// CHECK-NEXT: Args: +// CHECK-NEXT: - String: 'heap allocated ref of type ''' +// CHECK-NEXT: - ValueType: Klass +// CHECK-NEXT: - String: '''' +// CHECK-NEXT: ... +public var global = Klass() // expected-remark {{heap allocated ref of type 'Klass'}} // CHECK: --- !Missed // CHECK-NEXT: Pass: sil-opt-remark-gen @@ -31,6 +42,17 @@ public func getGlobal() -> Klass { // expected-note @-19:12 {{of 'global'}} } +// CHECK: --- !Missed +// CHECK-NEXT: Pass: sil-opt-remark-gen +// CHECK-NEXT: Name: sil.memory +// CHECK-NEXT: DebugLoc: { File: '{{.*}}opt-remark-generator-yaml.swift', +// CHECK-NEXT: Line: [[# @LINE + 51]], Column: 11 } +// CHECK-NEXT: Function: 'useGlobal()' +// CHECK-NEXT: Args: +// CHECK-NEXT: - String: 'heap allocated ref of type ''' +// CHECK-NEXT: - ValueType: +// CHECK-NEXT: - String: '''' +// CHECK-NEXT: ... // CHECK-NEXT: --- !Missed // CHECK-NEXT: Pass: sil-opt-remark-gen // CHECK-NEXT: Name: sil.memory @@ -75,10 +97,11 @@ public func useGlobal() { let x = getGlobal() // Make sure that the retain msg is at the beginning of the print and the // releases are the end of the print. - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:9 {{of 'x'}} + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-5:9 {{of 'x'}} // We test the type emission above since FileCheck can handle regex. - // expected-remark @-3:12 {{release of type}} - // expected-remark @-4:12 {{release of type 'Klass'}} - // expected-note @-8:9 {{of 'x'}} + // expected-remark @-4:12 {{release of type}} + // expected-remark @-5:12 {{release of type 'Klass'}} + // expected-note @-9:9 {{of 'x'}} } diff --git a/test/SILOptimizer/opt-remark-generator.swift b/test/SILOptimizer/opt-remark-generator.swift index 9b06fc17a76c6..8c780ea9f571b 100644 --- a/test/SILOptimizer/opt-remark-generator.swift +++ b/test/SILOptimizer/opt-remark-generator.swift @@ -5,7 +5,9 @@ public class Klass {} -public var global = Klass() +// TODO: Change global related code to be implicit/autogenerated (as +// appropriate) so we don't emit this remark. +public var global = Klass() // expected-remark {{heap allocated ref of type 'Klass'}} @inline(never) public func getGlobal() -> Klass { @@ -13,15 +15,20 @@ public func getGlobal() -> Klass { // expected-note @-5:12 {{of 'global'}} } +// Make sure that the retain msg is at the beginning of the print and the +// releases are the end of the print. +// +// The heap allocated ref is for the temporary array and the release that is +// unannotated is for that array as well. We make sure that the heap allocated +// ref is on the argument that necessitated its creation. public func useGlobal() { let x = getGlobal() - // Make sure that the retain msg is at the beginning of the print and the - // releases are the end of the print. - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:9 {{of 'x'}} - // expected-remark @-2:12 {{release of type}} - // expected-remark @-3:12 {{release of type 'Klass'}} - // expected-note @-7:9 {{of 'x'}} + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-3:9 {{of 'x'}} + // expected-remark @-3:12 {{release of type}} + // expected-remark @-4:12 {{release of type 'Klass'}} + // expected-note @-6:9 {{of 'x'}} } public enum TrivialState { @@ -36,16 +43,16 @@ struct StructWithOwner { } func printStructWithOwner(x : StructWithOwner) { - print(x) // expected-remark {{retain of type 'Klass'}} - // expected-note @-2:27 {{of 'x.owner'}} - // We should be able to infer the arg here. + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'Klass'}} + // expected-note @-3:27 {{of 'x.owner'}} // expected-remark @-3:12 {{release of type}} } func printStructWithOwnerOwner(x : StructWithOwner) { - print(x.owner) // expected-remark {{retain of type 'Klass'}} - // expected-note @-2:32 {{of 'x.owner'}} - // We should be able to infer the arg here. + print(x.owner) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'Klass'}} + // expected-note @-3:32 {{of 'x.owner'}} // expected-remark @-3:18 {{release of type}} } @@ -67,19 +74,19 @@ struct KlassPair { func printKlassPair(x : KlassPair) { // We pattern match columns to ensure we get retain on the p and release on // the end ')' - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:21 {{of 'x.lhs'}} - // expected-remark @-2:5 {{retain of type 'Klass'}} - // expected-note @-6:21 {{of 'x.rhs'}} - // This is a release for Array for print. + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-5:21 {{of 'x.lhs'}} + // expected-remark @-3:5 {{retain of type 'Klass'}} + // expected-note @-7:21 {{of 'x.rhs'}} // expected-remark @-5:12 {{release of type}} } func printKlassPairLHS(x : KlassPair) { // We print the remarks at the 'p' and at the ending ')'. - print(x.lhs) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-3:24 {{of 'x.lhs'}} - // Release for Array needed for print. + print(x.lhs) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-4:24 {{of 'x.lhs'}} // expected-remark @-3:16 {{release of type}} } @@ -98,20 +105,21 @@ func callingAnInitializerKlassPair(x: Klass, y: Klass) -> KlassPair { func printKlassTuplePair(x : (Klass, Klass)) { // We pattern match columns to ensure we get retain on the p and release on // the end ')' - print(x) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-4:26 {{of 'x'}} - // expected-remark @-2:5 {{retain of type 'Klass'}} - // expected-note @-6:26 {{of 'x'}} - // Release on temp array for print(...). + print(x) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-5:26 {{of 'x'}} + // expected-remark @-3:5 {{retain of type 'Klass'}} + // expected-note @-7:26 {{of 'x'}} // expected-remark @-5:12 {{release of type}} } func printKlassTupleLHS(x : (Klass, Klass)) { // We print the remarks at the 'p' and at the ending ')'. - print(x.0) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-3:25 {{of 'x'}} + print(x.0) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-4:25 {{of 'x'}} // Release on Array for print. - // expected-remark @-3:14 {{release of type}} + // expected-remark @-4:14 {{release of type}} } func returnKlassTupleLHS(x: (Klass, Klass)) -> Klass { @@ -179,19 +187,22 @@ func castAsQuestionDiamondGEP2(x: KlassPair) { // expected-remark @-2:39 {{retain of type 'Klass'}} // expected-note @-4 {{of 'x.rhs'}} case let (.some(x1), .some(x2)): - print(x1, x2) // expected-remark {{retain of type 'Optional'}} + print(x1, x2) // expected-remark @:15 {{heap allocated ref of type}} // expected-remark @-1 {{retain of type 'Optional'}} - // expected-remark @-2 {{release of type}} - // expected-remark @-3 {{release of type 'Optional'}} + // expected-remark @-2 {{retain of type 'Optional'}} + // expected-remark @-3 {{release of type}} // expected-remark @-4 {{release of type 'Optional'}} + // expected-remark @-5 {{release of type 'Optional'}} case let (.some(x1), nil): - print(x1) // expected-remark {{retain of type 'SubKlass'}} - // expected-remark @-1 {{release of type}} - // expected-remark @-2 {{release of type 'Optional'}} + print(x1) // expected-remark @:15 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'SubKlass'}} + // expected-remark @-2 {{release of type}} + // expected-remark @-3 {{release of type 'Optional'}} case let (nil, .some(x2)): - print(x2) // expected-remark {{retain of type 'SubKlass'}} - // expected-remark @-1 {{release of type}} - // expected-remark @-2 {{release of type 'Optional'}} + print(x2) // expected-remark @:15 {{heap allocated ref of type}} + // expected-remark @-1 {{retain of type 'SubKlass'}} + // expected-remark @-2 {{release of type}} + // expected-remark @-3 {{release of type 'Optional'}} case (nil, nil): break } @@ -237,9 +248,10 @@ func inoutKlassQuestionCastArgument2(x: inout Klass?) -> SubKlass? { // underlying Array type name changing under the hood in between platforms. @inline(__always) func alwaysInlineCallee(_ calleeX: Klass) { - print(calleeX) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-2:27 {{of 'calleeX'}} - // expected-remark @-2:18 {{release of type}} + print(calleeX) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-3:27 {{of 'calleeX'}} + // expected-remark @-3:18 {{release of type}} } // We should have 3x rr remarks here on callerX and none on calleeX. All of the @@ -247,13 +259,28 @@ func alwaysInlineCallee(_ calleeX: Klass) { // // TODO: Should we print out as notes the whole inlined call stack? func alwaysInlineCaller(_ callerX: Klass) { - alwaysInlineCallee(callerX) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-2:27 {{of 'callerX'}} - // expected-remark @-2:31 {{release of type}} - print(callerX) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-5:27 {{of 'callerX'}} - // expected-remark @-2:18 {{release of type}} - alwaysInlineCallee(callerX) // expected-remark @:5 {{retain of type 'Klass'}} - // expected-note @-8:27 {{of 'callerX'}} - // expected-remark @-2:31 {{release of type}} + alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-3:27 {{of 'callerX'}} + // expected-remark @-3:31 {{release of type}} + print(callerX) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-7:27 {{of 'callerX'}} + // expected-remark @-3:18 {{release of type}} + alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-11:27 {{of 'callerX'}} + // expected-remark @-3:31 {{release of type}} +} + +func allocateValue() { + // Remark should be on Klass and note should be on k. + let k = Klass() // expected-remark @:13 {{heap allocated ref of type 'Klass'}} + // expected-note @-1:9 {{of 'k'}} + print(k) // expected-remark @:11 {{heap allocated ref of type}} + // expected-remark @-1:5 {{retain of type 'Klass'}} + // expected-note @-4:9 {{of 'k'}} + // expected-remark @-3:12 {{release of type}} + // expected-remark @-4:12 {{release of type 'Klass'}} + // expected-note @-7:9 {{of 'k'}} } From 303026b574227c2df5aecf2204f1d27f7b5ae5f9 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Sun, 23 Aug 2020 16:43:29 -0700 Subject: [PATCH 286/663] Don't drop -DNDEBUG from CMAKE_CXX_FLAGS_RELEASE (#33565) * Don't drop -DNDEBUG from CMAKE_CXX_FLAGS_RELEASE * Add comment --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf0d50a51948d..b85c876071459 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -635,9 +635,10 @@ endif() if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) # CMake's default for CMAKE_CXX_FLAGS_RELEASE is "-O3 -DNDEBUG". Let's avoid "-O3" for consistency - # between Release and RelWithDebInfo. And let's not set -DNDEBUG because we're setting that manually - # based on LLVM_ENABLE_ASSERTIONS. - set(CMAKE_CXX_FLAGS_RELEASE "-O2") + # between Release and RelWithDebInfo. Dropping -DNDEBUG from this setting is blocked by triggering + # a test failure of Swift-Unit :: Syntax/./SwiftSyntaxTests/TypeSyntaxTests.MetatypeTypeWithAPIs + # because unit tests don't currently explicitly set -DNDEBUG/-UNDEBUG. + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") _compute_lto_flag("${SWIFT_TOOLS_ENABLE_LTO}" _lto_flag_out) if(_lto_flag_out) From 35b4925ee97544ef411c386b190ddb11a666154f Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sun, 23 Aug 2020 21:01:19 -0700 Subject: [PATCH 287/663] Add warning about spaces in the Xcode path. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a88ba8b00a4c7..11da346e95932 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ Please make sure you use Python 2.x. Python 3.x is not supported currently. To build for macOS, you need [Xcode 12 beta 3](https://developer.apple.com/xcode/resources/). The required version of Xcode changes frequently, and is often a beta release. Check this document or the host information on for the -current required version. +current required version. The path name for the Xcode app must not include any spaces. You will also need [CMake](https://cmake.org) and [Ninja](https://ninja-build.org), which can be installed via a package manager: From 970824706513f8a62c5f8ca01837ddc499f8583e Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Sun, 9 Feb 2020 19:52:39 -0800 Subject: [PATCH 288/663] [SE-0284] Lift the 1-vararg-per-function restriction [SE-0284] Add round_trip_parse_gen tests [SE-0284] Add missing test cases --- include/swift/AST/DiagnosticsParse.def | 4 +- lib/Parse/ParsePattern.cpp | 28 +++-- test/Constraints/argument_matching.swift | 107 ++++++++++++++++++ test/Interpreter/multiple_varargs.swift | 85 ++++++++++++++ test/SILGen/arguments.swift | 8 ++ .../round_trip_parse_gen.swift.withkinds | 9 +- test/Syntax/round_trip_parse_gen.swift | 5 +- test/decl/func/vararg.swift | 33 +++++- 8 files changed, 257 insertions(+), 22 deletions(-) create mode 100644 test/Interpreter/multiple_varargs.swift diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 6c7f4e6533b04..b9b1604135913 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -882,8 +882,6 @@ ERROR(expected_parameter_colon,PointsToFirstBadToken, "expected ':' following argument label and parameter name", ()) ERROR(expected_assignment_instead_of_comparison_operator,none, "expected '=' instead of '==' to assign default value for parameter", ()) -ERROR(multiple_parameter_ellipsis,none, - "only a single variadic parameter '...' is permitted", ()) ERROR(parameter_vararg_default,none, "variadic parameter cannot have a default value", ()) ERROR(parameter_specifier_as_attr_disallowed,none, @@ -916,6 +914,8 @@ ERROR(initializer_as_typed_pattern,none, ERROR(unlabeled_parameter_following_variadic_parameter,none, "a parameter following a variadic parameter requires a label", ()) +ERROR(closure_unlabeled_parameter_following_variadic_parameter,none, + "no parameters may follow a variadic parameter in a closure", ()) ERROR(enum_element_empty_arglist,none, "enum element with associated values must have at least one " diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index e26a0dd1cd238..130a32b0a6f67 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -572,7 +572,6 @@ mapParsedParameters(Parser &parser, // Collect the elements of the tuple patterns for argument and body // parameters. SmallVector elements; - SourceLoc ellipsisLoc; for (auto ¶m : params) { // Whether the provided name is API by default depends on the parameter @@ -623,27 +622,26 @@ mapParsedParameters(Parser &parser, } // Warn when an unlabeled parameter follows a variadic parameter - if (ellipsisLoc.isValid() && elements.back()->isVariadic() && - param.FirstName.empty()) { - parser.diagnose(param.FirstNameLoc, - diag::unlabeled_parameter_following_variadic_parameter); + if (!elements.empty() && elements.back()->isVariadic() && argName.empty()) { + // Closure parameters can't have external labels, so use a more specific + // diagnostic. + if (paramContext == Parser::ParameterContextKind::Closure) + parser.diagnose( + param.FirstNameLoc, + diag::closure_unlabeled_parameter_following_variadic_parameter); + else + parser.diagnose(param.FirstNameLoc, + diag::unlabeled_parameter_following_variadic_parameter); } - - // If this parameter had an ellipsis, check whether it's the last parameter. - if (param.EllipsisLoc.isValid()) { - if (ellipsisLoc.isValid()) { - parser.diagnose(param.EllipsisLoc, diag::multiple_parameter_ellipsis) - .highlight(ellipsisLoc) - .fixItRemove(param.EllipsisLoc); - param.EllipsisLoc = SourceLoc(); - } else if (!result->getTypeRepr()) { + // If this parameter had an ellipsis, check it has a TypeRepr. + if (param.EllipsisLoc.isValid()) { + if (!result->getTypeRepr()) { parser.diagnose(param.EllipsisLoc, diag::untyped_pattern_ellipsis) .highlight(result->getSourceRange()); param.EllipsisLoc = SourceLoc(); } else { - ellipsisLoc = param.EllipsisLoc; result->setVariadic(); } } diff --git a/test/Constraints/argument_matching.swift b/test/Constraints/argument_matching.swift index c29b9c9649997..c321aa3e739a2 100644 --- a/test/Constraints/argument_matching.swift +++ b/test/Constraints/argument_matching.swift @@ -305,6 +305,93 @@ variadics6(x: 1, 2, 3) // expected-error{{missing argument for parameter 'z' in variadics6(x: 1) // expected-error{{missing argument for parameter 'z' in call}} variadics6() // expected-error{{missing argument for parameter 'z' in call}} +func variadics7(_ x: Int..., y: Int...) { } + +// Using multiple variadics (in order, complete) +variadics7(1, y: 2) +variadics7(1, 2, 3, y: 4, 5, 6) +variadics7(1, 2, y: 2) +variadics7(1, y: 2, 1) + +// multiple variadics, in order, some missing +variadics7(y: 1) +variadics7(1) +variadics7(y: 4, 5, 6) +variadics7(1, 2, 3) + +func variadics8(x: Int..., y: Int...) { } + +// multiple variadics, out of order +variadics8(y: 1, x: 2) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 2, }} {{16-22=}} +variadics8(y: 1, 2, 3, x: 4) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 4, }} {{22-28=}} +variadics8(y: 1, x: 2, 3, 4) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 2, 3, 4, }} {{16-28=}} +variadics8(y: 1, 2, 3, x: 4, 5, 6) // expected-error {{argument 'x' must precede argument 'y'}} {{12-12=x: 4, 5, 6, }} {{22-34=}} + +func variadics9(_ a: Int..., b: Int, _ c: Int...) { } // expected-note {{'variadics9(_:b:_:)' declared here}} + +// multiple split variadics, in order, complete +variadics9(1, b: 2, 3) +variadics9(1, 2, 3, b: 2, 3) +variadics9(1, b: 2, 3, 2, 1) +variadics9(1, 2, 3, b: 2, 3, 2, 1) + +// multiple split variadics, in order, some missing +variadics9(b: 2, 3) +variadics9(1, b: 2) +variadics9(1, 2, b: 2) +variadics9(b: 2, 3, 2, 1) + +// multiple split variadics, required missing +variadics9(1) // expected-error {{missing argument for parameter 'b' in call}} + +func variadics10(_ a: Int..., b: Int = 2, _ c: Int...) { } + +// multiple unlabeled variadics split by defaulted param, in order, complete +variadics10(1, b: 2, 3) +variadics10(1, 2, 3, b: 2, 3) +variadics10(1, b: 2, 3, 2, 1) +variadics10(1, 2, 3, b: 2, 3, 2, 1) + +// multiple unlabeled variadics split by defaulted param, in order, some missing +variadics10(1, 2, 3) +variadics10(1, 2, 3, b: 3) +variadics10(b: 3) + +func variadics11(_ a: Int..., b: Bool = false, _ c: String...) { } + +variadics11(1, 2, 3, b: true, "hello", "world") +variadics11(b: true, "hello", "world") +variadics11(1, 2, 3, b: true) +variadics11(b: true) +variadics11() +variadics11(1, 2, 3, "hello", "world") // expected-error 2 {{cannot convert value of type 'String' to expected argument type 'Int'}} + +func variadics12(a: Int..., b: Int, c: Int...) { } + +variadics12(a: 1, 2, 3, b: 4, c: 5, 6, 7) +variadics12(b: 4, c: 5, 6, 7) +variadics12(a: 1, 2, 3, b: 4) + +variadics12(c: 5, 6, 7, b: 4, a: 1, 2, 3) // expected-error {{incorrect argument labels in call (have 'c:_:_:b:a:_:_:', expected 'a:b:c:')}} {{13-14=a}} {{19-19=b: }} {{22-22=c: }} {{25-28=}} {{31-34=}} + + +// Edge cases involving multiple trailing closures and forward matching. +func variadics13(a: Int..., b: (()->Void)...) {} + +variadics13() +variadics13(a: 1, 2, 3) {} _: {} _: {} +variadics13() {} _: {} _: {} +variadics13(a: 1, 2, 3) +variadics13(a: 1, 2, 3) {} + +func variadics14(a: (()->Void)..., b: (()->Void)...) {} // expected-note {{'variadics14(a:b:)' declared here}} + +variadics14(a: {}, {}, b: {}, {}) +variadics14(a: {}, {}) {} _: {} +variadics14 {} _: {} b: {} _: {} +variadics14 {} b: {} +variadics14 {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with 'b' to suppress this warning}} + func outOfOrder(_ a : Int, b: Int) { outOfOrder(b: 42, 52) // expected-error {{unnamed argument #2 must precede argument 'b'}} {{14-14=52, }} {{19-23=}} } @@ -1336,6 +1423,26 @@ d = sub2[d] // expected-error{{missing argument label 'd:' in subscript}} {{10-1 d = sub2[d: d] d = sub2[f: d] // expected-error{{incorrect argument label in subscript (have 'f:', expected 'd:')}} {{10-11=d}} +struct Sub3 { + subscript (a: Int..., b b: Int...) -> Int { 42 } +} + +let sub3 = Sub3() +_ = sub3[1, 2, 3, b: 4, 5, 6] +_ = sub3[b: 4, 5, 6] +_ = sub3[1, 2, 3] +_ = sub3[1, c: 4] // expected-error {{incorrect argument label in subscript (have '_:c:', expected '_:b:')}} + +struct Sub4 { + subscript (a: Int..., b b: Int = 0, c: Int...) -> Int { 42 } +} + +let sub4 = Sub4() +_ = sub4[1, 2, 3, b: 2, 1, 2, 3] +_ = sub4[1, 2, 3, b: 2] +_ = sub4[1, 2, 3] +_ = sub4[] + // ------------------------------------------- // Closures // ------------------------------------------- diff --git a/test/Interpreter/multiple_varargs.swift b/test/Interpreter/multiple_varargs.swift new file mode 100644 index 0000000000000..372b49640a3f4 --- /dev/null +++ b/test/Interpreter/multiple_varargs.swift @@ -0,0 +1,85 @@ +// RUN: %target-run-simple-swift | %FileCheck %s + +// REQUIRES: executable_test + +func vf(x: Int..., y: Int...) { + print(x, y) +} + +vf(x: 1, 2, 3, y: 4, 5, 6) +// CHECK: [1, 2, 3] [4, 5, 6] +vf(y: 1, 2) +// CHECK: [] [1, 2] +vf(x: 3, 4) +// CHECK: [3, 4] [] + +func vf2(_ x: Int..., y: Int, _ z: Int...) { + print(x, y, z) +} + +vf2(1, 2, 3, y: 4, 5, 6, 7) +// CHECK: [1, 2, 3] 4 [5, 6, 7] +vf2(y: 4, 5, 6, 7) +// CHECK: [] 4 [5, 6, 7] +vf2(1, 2, 3, y: 4) +// CHECK: [1, 2, 3] 4 [] +vf2(y: 4) +// CHECK: [] 4 [] + +func vf3(_ x: Int..., y: Int = 42, _ z: Int...) { + print(x, y, z) +} + +vf3(1, 2, 3, y: 4, 5, 6, 7) +// CHECK: [1, 2, 3] 4 [5, 6, 7] +vf3(y: 4, 5, 6, 7) +// CHECK: [] 4 [5, 6, 7] +vf3(1, 2, 3, y: 4) +// CHECK: [1, 2, 3] 4 [] +vf3(y: 4) +// CHECK: [] 4 [] + +vf3() +// CHECK: [] 42 [] +vf3(1, 2, 3) +// CHECK: [1, 2, 3] 42 [] + +func foo(a: Int..., b: Int, c: Int..., d: Int) { + print("one") +} + +func foo(a: [Int], b: Int, c: [Int], d: Int) { + print("two") +} + +func foo(a: Int..., b: Int, c: [Int], d: Int) { + print("three") +} + +foo(a: 1, 2, 3, b: 4, c: 5, 6, 7, d: 8) +// CHECK: one +foo(a: [1, 2, 3], b: 4, c: [5, 6, 7], d: 8) +// CHECK: two +foo(a: 1, 2, 3, b: 4, c: [5, 6, 7], d: 8) +// CHECK: three + +struct Baz { + init(a: Int..., b: Int...) { + print(a, b) + } + + init(_ a: Int..., b: String, _ c: Int...) { + print(a, b, c) + } + + subscript(a: Int..., b b: Int...) -> [Int] { a + b } +} + +let baz1 = Baz(a: 1, 2, 3, b: 4, 5, 6) +// CHECK: [1, 2, 3] [4, 5, 6] + +let baz2 = Baz(1, 2, 3, b: "hello, world!", 3, 2, 1) +// CHECK: [1, 2, 3] hello, world! [3, 2, 1] + +print(baz1[1, 2, b: 3, 4]) +// CHECK: [1, 2, 3, 4] diff --git a/test/SILGen/arguments.swift b/test/SILGen/arguments.swift index fdd26f1594c9a..0c16ad45910c9 100644 --- a/test/SILGen/arguments.swift +++ b/test/SILGen/arguments.swift @@ -82,6 +82,14 @@ func variadic_arg_3(_ y: Float..., x: Int) {} // CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_3{{[_0-9a-zA-Z]*}}F // CHECK: bb0([[Y:%[0-9]+]] : $Array, [[X:%[0-9]+]] : $Int): +func variadic_arg_4(_ y: Float..., x: Int...) {} +// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_4{{[_0-9a-zA-Z]*}}F +// CHECK: bb0([[Y:%[0-9]+]] : $Array, [[X:%[0-9]+]] : $Array): + +func variadic_arg_5(a: Int, b: Float..., c: Int, d: Int...) {} +// CHECK-LABEL: sil hidden [ossa] @$ss14variadic_arg_5{{[_0-9a-zA-Z]*}}F +// CHECK: bb0([[A:%[0-9]+]] : $Int, [[B:%[0-9]+]] : $Array, [[C:%[0-9]+]] : $Int, [[D:%[0-9]+]] : $Array): + variadic_arg_3(x: i) variadic_arg_3(f, x: i) variadic_arg_3(f, f, f, x: i) diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds index 43bd7aa16e71e..61dfcac3126bb 100644 --- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds @@ -102,13 +102,15 @@ class C { @objc private init(a: Int) init!(a: Int) {} init?(a: Int) {} - public init(a: Int) throws {} + public init(a: Int) throws {} + init(a: Int..., b: Double...) {} @objc deinit {} private deinit {} internal subscript(x: Int) -> Int { get {} set {} } - subscript() -> Int { return 1 } + subscript() -> Int { return 1 } + subscript(x: Int..., y y: String...) -> Int { return 1 } var x: Int { address { fatalError() } @@ -197,7 +199,8 @@ func foo(_ _: Int = true ? 2: 3, @objc e: X = true, f: inout Int, - g: Int...) throws -> [Int: String] {} + g: Int..., + h: Bool...) throws -> [Int: String] {} func foo(_ a: Int) throws -> Int {} func foo( a: Int) rethrows -> Int {} diff --git a/test/Syntax/round_trip_parse_gen.swift b/test/Syntax/round_trip_parse_gen.swift index 8c4c998fb49cb..6c68ff5aadae2 100644 --- a/test/Syntax/round_trip_parse_gen.swift +++ b/test/Syntax/round_trip_parse_gen.swift @@ -103,12 +103,14 @@ class C { init!(a: Int) {} init?(a: Int) {} public init(a: Int) throws {} + init(a: Int..., b: Double...) {} @objc deinit {} private deinit {} internal subscript(x: Int) -> Int { get {} set {} } subscript() -> Int { return 1 } + subscript(x: Int..., y y: String...) -> Int { return 1 } var x: Int { address { fatalError() } @@ -197,7 +199,8 @@ func foo(_ _: Int, d _: Int = true ? 2: 3, @objc e: X = true, f: inout Int, - g: Int...) throws -> [Int: String] {} + g: Int..., + h: Bool...) throws -> [Int: String] {} func foo(_ a: Int) throws -> Int {} func foo( a: Int) rethrows -> Int {} diff --git a/test/decl/func/vararg.swift b/test/decl/func/vararg.swift index 36bda36730f59..71befae75ef90 100644 --- a/test/decl/func/vararg.swift +++ b/test/decl/func/vararg.swift @@ -27,7 +27,38 @@ func invalidVariadic(_ e: NonExistentType) { // expected-error {{cannot find typ { (e: ExtraCrispy...) in }() // expected-error {{cannot find type 'ExtraCrispy' in scope}} } -func twoVariadics(_ a: Int..., b: Int...) { } // expected-error{{only a single variadic parameter '...' is permitted}} {{38-41=}} +func twoVariadics(_ a: Int..., b: Int...) { } +func unlabeledFollowingVariadic(_ a: Int..., _ b: Int) { } // expected-error {{a parameter following a variadic parameter requires a label}} +func unlabeledVariadicFollowingVariadic(_ a: Int..., _ b: Int...) { } // expected-error {{a parameter following a variadic parameter requires a label}} +func unlabeledFollowingTwoVariadics(_ a: Int..., b: Int..., _ c: Int) { } // expected-error {{a parameter following a variadic parameter requires a label}} +func splitVariadics(_ a: Int..., b: Int, _ c: String...) { } +func splitByDefaultArgVariadics(_ a: Int..., b: Int = 0, _ c: String...) { } + +struct HasSubscripts { + subscript(a: Int...) -> Void { () } + subscript(a: Int..., b b: Int...) -> Void { () } + subscript(a: Int..., b: Int...) -> Void { () } // expected-error {{a parameter following a variadic parameter requires a label}} + subscript(a: Int..., b: Int) -> Void { () } // expected-error {{a parameter following a variadic parameter requires a label}} + subscript(a: Int..., b b: Int..., c c: Int) -> Void { () } + subscript(a: Int..., b b: Int..., c: Int) -> Void { () } // expected-error {{a parameter following a variadic parameter requires a label}} + subscript(a: Int..., c c: Int = 0, b: Int...) -> Void { () } + subscript(a: Int..., b: String = "hello, world!") -> Bool { false } // expected-error {{a parameter following a variadic parameter requires a label}} +} + +struct HasInitializers { + init(a: Int...) {} + init(a: Int..., b: Int...) {} + init(a: Int..., _ b: Int...) {} // expected-error {{a parameter following a variadic parameter requires a label}} + init(a: Int..., c: Int = 0, _ b: Int...) {} +} + +let closure = {(x: Int..., y: Int...) in } // expected-error {{no parameters may follow a variadic parameter in a closure}} +let closure2 = {(x: Int..., y: Int) in } // expected-error {{no parameters may follow a variadic parameter in a closure}} +let closure3 = {(x: Int..., y: Int, z: Int...) in } // expected-error {{no parameters may follow a variadic parameter in a closure}} +let closure4 = {(x: Int...) in } +let closure5 = {(x: Int, y: Int...) in } +let closure6 = {(x: Int..., y z: Int) in } // expected-error {{closure cannot have keyword arguments}} +// expected-error@-1 {{no parameters may follow a variadic parameter in a closure}} // rdar://22056861 func f5(_ list: Any..., end: String = "") {} From 84928c611d2349bda5a865db251d83f98ee29091 Mon Sep 17 00:00:00 2001 From: Valeriy Van Date: Mon, 24 Aug 2020 13:43:25 +0200 Subject: [PATCH 289/663] Fixes example snippet in Array.swift Uses URL instead of NSURL, otherwise example deson't compile --- stdlib/public/core/Array.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index fd72700ca95b8..42fcd9d672e44 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -264,7 +264,7 @@ /// let colors = ["periwinkle", "rose", "moss"] /// let moreColors: [String?] = ["ochre", "pine"] /// -/// let url = NSURL(fileURLWithPath: "names.plist") +/// let url = URL(fileURLWithPath: "names.plist") /// (colors as NSArray).write(to: url, atomically: true) /// // true /// From fe0a945898df49b2981ecd97618682fbf7d6a392 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sun, 23 Aug 2020 15:30:43 -0700 Subject: [PATCH 290/663] AST: split out diagnostics serialization Create a new diagnostics serialization library, splitting out of swiftAST to reduce the overheads for building the tooling for cross-compiling the toolchain. This should reduce the build time for swift-serialize-diagnostics to enable cross-compilation. --- include/swift/AST/DiagnosticEngine.h | 2 +- include/swift/{AST => Localization}/LocalizationFormat.h | 0 lib/AST/CMakeLists.txt | 1 - lib/AST/DiagnosticEngine.cpp | 2 +- lib/CMakeLists.txt | 1 + lib/Frontend/CMakeLists.txt | 1 + lib/Localization/CMakeLists.txt | 6 ++++++ lib/{AST => Localization}/LocalizationFormat.cpp | 2 +- tools/swift-serialize-diagnostics/CMakeLists.txt | 5 ++--- .../swift-serialize-diagnostics.cpp | 2 +- 10 files changed, 14 insertions(+), 8 deletions(-) rename include/swift/{AST => Localization}/LocalizationFormat.h (100%) create mode 100644 lib/Localization/CMakeLists.txt rename lib/{AST => Localization}/LocalizationFormat.cpp (99%) diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 88f6385a7607c..6d4fe61bbd4e2 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -20,8 +20,8 @@ #include "swift/AST/DeclNameLoc.h" #include "swift/AST/DiagnosticConsumer.h" -#include "swift/AST/LocalizationFormat.h" #include "swift/AST/TypeLoc.h" +#include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/Localization/LocalizationFormat.h similarity index 100% rename from include/swift/AST/LocalizationFormat.h rename to include/swift/Localization/LocalizationFormat.h diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 71a1cfa05c1ea..62993edae03ea 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -57,7 +57,6 @@ add_swift_host_library(swiftAST STATIC IndexSubset.cpp InlinableText.cpp LayoutConstraint.cpp - LocalizationFormat.cpp Module.cpp ModuleDependencies.cpp ModuleLoader.cpp diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 5719cc55f62d2..f7b9368589bfa 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -20,7 +20,6 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticSuppression.h" -#include "swift/AST/LocalizationFormat.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/PrintOptions.h" @@ -28,6 +27,7 @@ #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" #include "swift/Config.h" +#include "swift/Localization/LocalizationFormat.h" #include "swift/Parse/Lexer.h" // bad dependency #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e82e1638b593a..8bada4e358315 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -27,6 +27,7 @@ add_subdirectory(IDE) add_subdirectory(Immediate) add_subdirectory(IRGen) add_subdirectory(LLVMPasses) +add_subdirectory(Localization) add_subdirectory(Markup) add_subdirectory(Migrator) add_subdirectory(Option) diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 0cb3c72b15b96..08988f9a078ee 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(swiftFrontend PRIVATE swiftSILGen swiftSILOptimizer swiftIRGen + swiftLocalization swiftSema swiftSerialization swiftTBDGen) diff --git a/lib/Localization/CMakeLists.txt b/lib/Localization/CMakeLists.txt new file mode 100644 index 0000000000000..5de7c352be6c5 --- /dev/null +++ b/lib/Localization/CMakeLists.txt @@ -0,0 +1,6 @@ + +add_swift_host_library(swiftLocalization STATIC + LocalizationFormat.cpp + + LLVM_LINK_COMPONENTS + support) diff --git a/lib/AST/LocalizationFormat.cpp b/lib/Localization/LocalizationFormat.cpp similarity index 99% rename from lib/AST/LocalizationFormat.cpp rename to lib/Localization/LocalizationFormat.cpp index 5bc4f46cf5e64..750a43651301a 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/Localization/LocalizationFormat.cpp @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -#include "swift/AST/LocalizationFormat.h" +#include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" diff --git a/tools/swift-serialize-diagnostics/CMakeLists.txt b/tools/swift-serialize-diagnostics/CMakeLists.txt index 13cf756c13c49..4a1ab49b59ed3 100644 --- a/tools/swift-serialize-diagnostics/CMakeLists.txt +++ b/tools/swift-serialize-diagnostics/CMakeLists.txt @@ -2,6 +2,5 @@ add_swift_host_tool(swift-serialize-diagnostics swift-serialize-diagnostics.cpp SWIFT_COMPONENT tools ) -target_link_libraries(swift-serialize-diagnostics - PRIVATE - swiftAST) +target_link_libraries(swift-serialize-diagnostics PRIVATE + swiftLocalization) diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp index 01ea696002637..03b0118f2eef4 100644 --- a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -14,9 +14,9 @@ // //===----------------------------------------------------------------------===// -#include "swift/AST/LocalizationFormat.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Basic/STLExtras.h" +#include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" From 8102d9194189760be7eb5512584cc8cbf0366ed8 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Fri, 21 Aug 2020 19:33:01 -0700 Subject: [PATCH 291/663] [AutoDiff] Make `DifferentiableActivityInfo::dump` print an end marker. End markers are useful for FileCheck. --- lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp b/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp index 3d1da0abb78fd..884f544a9d5f4 100644 --- a/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp @@ -557,6 +557,8 @@ void DifferentiableActivityInfo::dump(SILAutoDiffIndices indices, for (auto &inst : bb) for (auto res : inst.getResults()) dump(res, indices, s); - s << '\n'; + if (std::next(bb.getIterator()) != fn.end()) + s << '\n'; } + s << "End activity info for " << fn.getName() << " at " << indices << "\n\n"; } From 7fcc7ba3c7d3101aba6c9e63aa423bb7963d2d0e Mon Sep 17 00:00:00 2001 From: Alex Efremov Date: Mon, 24 Aug 2020 19:26:02 +0200 Subject: [PATCH 292/663] Fix JVPs for `Float` `*=` and `/=` (#33579) JVPs for `*=` and `/=` were specified incorrectly. From 48c048f34d3e28743f2c7b88a013a22b76d79bf3 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Fri, 21 Aug 2020 19:34:54 -0700 Subject: [PATCH 293/663] [AutoDiff] Fix PullbackCloner tangent value category mismatch issues. Fix SIL pullback function type calculation: remap original `unowned` results to the correct pullback parameter convention depending on the `TangentVector` type lowering. Make `PullbackCloner` visitors for the following instructions check and handle tangent value categories: `struct`, `struct_extract`, `tuple`, `destructure_tuple`. Add differentiation tests for `Optional` struct and class stored properties, exercising the instruction visitors above. Resolves SR-13430. --- lib/SIL/IR/SILFunctionType.cpp | 6 +- .../Differentiation/PullbackCloner.cpp | 363 ++++++++++++------ .../Differentiation/VJPCloner.cpp | 6 +- .../validation-test/optional-property.swift | 207 ++++++++++ test/AutoDiff/validation-test/optional.swift | 7 +- 5 files changed, 463 insertions(+), 126 deletions(-) create mode 100644 test/AutoDiff/validation-test/optional-property.swift diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 0e50bdd34f8e4..f37e6fc933656 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -538,6 +538,8 @@ static CanSILFunctionType getAutoDiffPullbackType( TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); ParameterConvention conv; switch (origResConv) { + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: case ResultConvention::Owned: case ResultConvention::Autoreleased: if (tl.isAddressOnly()) { @@ -547,10 +549,6 @@ static CanSILFunctionType getAutoDiffPullbackType( : ParameterConvention::Direct_Guaranteed; } break; - case ResultConvention::Unowned: - case ResultConvention::UnownedInnerPointer: - conv = ParameterConvention::Direct_Unowned; - break; case ResultConvention::Indirect: conv = ParameterConvention::Indirect_In_Guaranteed; break; diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 9de979b76d0f8..7d0c30644f9e0 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -1011,28 +1011,68 @@ class PullbackCloner::Implementation final auto *bb = si->getParent(); auto loc = si->getLoc(); auto *structDecl = si->getStructDecl(); - auto av = getAdjointValue(bb, si); - switch (av.getKind()) { - case AdjointValueKind::Zero: - for (auto *field : structDecl->getStoredProperties()) { - auto fv = si->getFieldValue(field); - addAdjointValue( - bb, fv, makeZeroAdjointValue(getRemappedTangentType(fv->getType())), - loc); + switch (getTangentValueCategory(si)) { + case SILValueCategory::Object: { + auto av = getAdjointValue(bb, si); + switch (av.getKind()) { + case AdjointValueKind::Zero: { + for (auto *field : structDecl->getStoredProperties()) { + auto fv = si->getFieldValue(field); + addAdjointValue( + bb, fv, + makeZeroAdjointValue(getRemappedTangentType(fv->getType())), loc); + } + break; } - break; - case AdjointValueKind::Concrete: { - auto adjStruct = materializeAdjointDirect(std::move(av), loc); - auto *dti = builder.createDestructureStruct(si->getLoc(), adjStruct); + case AdjointValueKind::Concrete: { + auto adjStruct = materializeAdjointDirect(std::move(av), loc); + auto *dti = builder.createDestructureStruct(si->getLoc(), adjStruct); - // Find the struct `TangentVector` type. - auto structTy = remapType(si->getType()).getASTType(); + // Find the struct `TangentVector` type. + auto structTy = remapType(si->getType()).getASTType(); #ifndef NDEBUG - auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); - assert(!getTypeLowering(tangentVectorTy).isAddressOnly()); - assert(tangentVectorTy->getStructOrBoundGenericStruct()); + auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); + assert(!getTypeLowering(tangentVectorTy).isAddressOnly()); + assert(tangentVectorTy->getStructOrBoundGenericStruct()); #endif + // Accumulate adjoints for the fields of the `struct` operand. + unsigned fieldIndex = 0; + for (auto it = structDecl->getStoredProperties().begin(); + it != structDecl->getStoredProperties().end(); + ++it, ++fieldIndex) { + VarDecl *field = *it; + if (field->getAttrs().hasAttribute()) + continue; + // Find the corresponding field in the tangent space. + auto *tanField = getTangentStoredProperty( + getContext(), field, structTy, loc, getInvoker()); + if (!tanField) { + errorOccurred = true; + return; + } + auto tanElt = dti->getResult(fieldIndex); + addAdjointValue(bb, si->getFieldValue(field), + makeConcreteAdjointValue(tanElt), si->getLoc()); + } + break; + } + case AdjointValueKind::Aggregate: { + // Note: All user-called initializations go through the calls to the + // initializer, and synthesized initializers only have one level of + // struct formation which will not result into any aggregate adjoint + // valeus. + llvm_unreachable( + "Aggregate adjoint values should not occur for `struct` " + "instructions"); + } + } + break; + } + case SILValueCategory::Address: { + auto adjBuf = getAdjointBuffer(bb, si); + // Find the struct `TangentVector` type. + auto structTy = remapType(si->getType()).getASTType(); // Accumulate adjoints for the fields of the `struct` operand. unsigned fieldIndex = 0; for (auto it = structDecl->getStoredProperties().begin(); @@ -1047,19 +1087,25 @@ class PullbackCloner::Implementation final errorOccurred = true; return; } - auto tanElt = dti->getResult(fieldIndex); - addAdjointValue(bb, si->getFieldValue(field), - makeConcreteAdjointValue(tanElt), si->getLoc()); + auto *adjFieldBuf = + builder.createStructElementAddr(loc, adjBuf, tanField); + auto fieldValue = si->getFieldValue(field); + switch (getTangentValueCategory(fieldValue)) { + case SILValueCategory::Object: { + auto adjField = builder.emitLoadValueOperation( + loc, adjFieldBuf, LoadOwnershipQualifier::Copy); + recordTemporary(adjField); + addAdjointValue(bb, fieldValue, makeConcreteAdjointValue(adjField), + loc); + break; + } + case SILValueCategory::Address: { + addToAdjointBuffer(bb, fieldValue, adjFieldBuf, loc); + break; + } + } } - break; - } - case AdjointValueKind::Aggregate: { - // Note: All user-called initializations go through the calls to the - // initializer, and synthesized initializers only have one level of struct - // formation which will not result into any aggregate adjoint valeus. - llvm_unreachable("Aggregate adjoint values should not occur for `struct` " - "instructions"); - } + } break; } } @@ -1071,41 +1117,75 @@ class PullbackCloner::Implementation final void visitStructExtractInst(StructExtractInst *sei) { auto *bb = sei->getParent(); auto loc = getValidLocation(sei); - auto structTy = remapType(sei->getOperand()->getType()).getASTType(); - auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); - assert(!getTypeLowering(tangentVectorTy).isAddressOnly()); - auto tangentVectorSILTy = SILType::getPrimitiveObjectType(tangentVectorTy); - auto *tangentVectorDecl = tangentVectorTy->getStructOrBoundGenericStruct(); - assert(tangentVectorDecl); // Find the corresponding field in the tangent space. + auto structTy = remapType(sei->getOperand()->getType()).getASTType(); auto *tanField = getTangentStoredProperty(getContext(), sei, structTy, getInvoker()); - assert(tanField && "Invalid projections should have been diagnosed"); - // Accumulate adjoint for the `struct_extract` operand. - auto av = getAdjointValue(bb, sei); - switch (av.getKind()) { - case AdjointValueKind::Zero: - addAdjointValue(bb, sei->getOperand(), - makeZeroAdjointValue(tangentVectorSILTy), loc); - break; - case AdjointValueKind::Concrete: - case AdjointValueKind::Aggregate: { - SmallVector eltVals; - for (auto *field : tangentVectorDecl->getStoredProperties()) { - if (field == tanField) { - eltVals.push_back(av); - } else { - auto substMap = tangentVectorTy->getMemberSubstitutionMap( - field->getModuleContext(), field); - auto fieldTy = field->getType().subst(substMap); - auto fieldSILTy = getTypeLowering(fieldTy).getLoweredType(); - assert(fieldSILTy.isObject()); - eltVals.push_back(makeZeroAdjointValue(fieldSILTy)); + // Check the `struct_extract` operand's value tangent category. + switch (getTangentValueCategory(sei->getOperand())) { + case SILValueCategory::Object: { + auto tangentVectorTy = getTangentSpace(structTy)->getCanonicalType(); + auto *tangentVectorDecl = + tangentVectorTy->getStructOrBoundGenericStruct(); + assert(tangentVectorDecl); + auto tangentVectorSILTy = + SILType::getPrimitiveObjectType(tangentVectorTy); + assert(tanField && "Invalid projections should have been diagnosed"); + // Accumulate adjoint for the `struct_extract` operand. + auto av = getAdjointValue(bb, sei); + switch (av.getKind()) { + case AdjointValueKind::Zero: + addAdjointValue(bb, sei->getOperand(), + makeZeroAdjointValue(tangentVectorSILTy), loc); + break; + case AdjointValueKind::Concrete: + case AdjointValueKind::Aggregate: { + SmallVector eltVals; + for (auto *field : tangentVectorDecl->getStoredProperties()) { + if (field == tanField) { + eltVals.push_back(av); + } else { + auto substMap = tangentVectorTy->getMemberSubstitutionMap( + field->getModuleContext(), field); + auto fieldTy = field->getType().subst(substMap); + auto fieldSILTy = getTypeLowering(fieldTy).getLoweredType(); + assert(fieldSILTy.isObject()); + eltVals.push_back(makeZeroAdjointValue(fieldSILTy)); + } } + addAdjointValue(bb, sei->getOperand(), + makeAggregateAdjointValue(tangentVectorSILTy, eltVals), + loc); } - addAdjointValue(bb, sei->getOperand(), - makeAggregateAdjointValue(tangentVectorSILTy, eltVals), - loc); + } + break; + } + case SILValueCategory::Address: { + auto adjBase = getAdjointBuffer(bb, sei->getOperand()); + auto *adjBaseElt = + builder.createStructElementAddr(loc, adjBase, tanField); + // Check the `struct_extract`'s value tangent category. + switch (getTangentValueCategory(sei)) { + case SILValueCategory::Object: { + auto adjElt = getAdjointValue(bb, sei); + auto concreteAdjElt = materializeAdjointDirect(adjElt, loc); + auto concreteAdjEltCopy = + builder.emitCopyValueOperation(loc, concreteAdjElt); + auto *alloc = builder.createAllocStack(loc, adjElt.getType()); + builder.emitStoreValueOperation(loc, concreteAdjEltCopy, alloc, + StoreOwnershipQualifier::Init); + accumulateIndirect(adjBaseElt, alloc, loc); + builder.createDestroyAddr(loc, alloc); + builder.createDeallocStack(loc, alloc); + break; + } + case SILValueCategory::Address: { + auto adjElt = getAdjointBuffer(bb, sei); + accumulateIndirect(adjBaseElt, adjElt, loc); + break; + } + } + break; } } } @@ -1171,52 +1251,73 @@ class PullbackCloner::Implementation final /// excluding non-differentiable elements void visitTupleInst(TupleInst *ti) { auto *bb = ti->getParent(); - auto av = getAdjointValue(bb, ti); - switch (av.getKind()) { - case AdjointValueKind::Zero: - for (auto elt : ti->getElements()) { - if (!getTangentSpace(elt->getType().getASTType())) - continue; - addAdjointValue( - bb, elt, - makeZeroAdjointValue(getRemappedTangentType(elt->getType())), - ti->getLoc()); + auto loc = ti->getLoc(); + switch (getTangentValueCategory(ti)) { + case SILValueCategory::Object: { + auto av = getAdjointValue(bb, ti); + switch (av.getKind()) { + case AdjointValueKind::Zero: + for (auto elt : ti->getElements()) { + if (!getTangentSpace(elt->getType().getASTType())) + continue; + addAdjointValue( + bb, elt, + makeZeroAdjointValue(getRemappedTangentType(elt->getType())), + loc); + } + break; + case AdjointValueKind::Concrete: { + auto adjVal = av.getConcreteValue(); + auto adjValCopy = builder.emitCopyValueOperation(loc, adjVal); + SmallVector adjElts; + if (!adjVal->getType().getAs()) { + recordTemporary(adjValCopy); + adjElts.push_back(adjValCopy); + } else { + auto *dti = builder.createDestructureTuple(loc, adjValCopy); + for (auto adjElt : dti->getResults()) + recordTemporary(adjElt); + adjElts.append(dti->getResults().begin(), dti->getResults().end()); + } + // Accumulate adjoints for `tuple` operands, skipping the + // non-`Differentiable` ones. + unsigned adjIndex = 0; + for (auto i : range(ti->getNumOperands())) { + if (!getTangentSpace(ti->getOperand(i)->getType().getASTType())) + continue; + auto adjElt = adjElts[adjIndex++]; + addAdjointValue(bb, ti->getOperand(i), + makeConcreteAdjointValue(adjElt), loc); + } + break; } - break; - case AdjointValueKind::Concrete: { - auto adjVal = av.getConcreteValue(); - unsigned adjIdx = 0; - auto adjValCopy = builder.emitCopyValueOperation(ti->getLoc(), adjVal); - SmallVector adjElts; - if (!adjVal->getType().getAs()) { - recordTemporary(adjValCopy); - adjElts.push_back(adjValCopy); - } else { - auto *dti = builder.createDestructureTuple(ti->getLoc(), adjValCopy); - for (auto adjElt : dti->getResults()) - recordTemporary(adjElt); - adjElts.append(dti->getResults().begin(), dti->getResults().end()); + case AdjointValueKind::Aggregate: + unsigned adjIndex = 0; + for (auto i : range(ti->getElements().size())) { + if (!getTangentSpace(ti->getElement(i)->getType().getASTType())) + continue; + addAdjointValue(bb, ti->getElement(i), + av.getAggregateElement(adjIndex++), loc); + } + break; } + break; + } + case SILValueCategory::Address: { + auto adjBuf = getAdjointBuffer(bb, ti); // Accumulate adjoints for `tuple` operands, skipping the - // non-differentiable ones. + // non-`Differentiable` ones. + unsigned adjIndex = 0; for (auto i : range(ti->getNumOperands())) { if (!getTangentSpace(ti->getOperand(i)->getType().getASTType())) continue; - auto adjElt = adjElts[adjIdx++]; - addAdjointValue(bb, ti->getOperand(i), makeConcreteAdjointValue(adjElt), - ti->getLoc()); + auto adjBufElt = + builder.createTupleElementAddr(loc, adjBuf, adjIndex++); + auto adjElt = getAdjointBuffer(bb, ti->getOperand(i)); + accumulateIndirect(adjElt, adjBufElt, loc); } break; } - case AdjointValueKind::Aggregate: - unsigned adjIdx = 0; - for (auto i : range(ti->getElements().size())) { - if (!getTangentSpace(ti->getElement(i)->getType().getASTType())) - continue; - addAdjointValue(bb, ti->getElement(i), av.getAggregateElement(adjIdx++), - ti->getLoc()); - } - break; } } @@ -1276,26 +1377,58 @@ class PullbackCloner::Implementation final /// adj[x].n += adj[yn] void visitDestructureTupleInst(DestructureTupleInst *dti) { auto *bb = dti->getParent(); + auto loc = dti->getLoc(); auto tupleTanTy = getRemappedTangentType(dti->getOperand()->getType()); - SmallVector adjValues; - for (auto origElt : dti->getResults()) { - if (!getTangentSpace(remapType(origElt->getType()).getASTType())) - continue; - adjValues.push_back(getAdjointValue(bb, origElt)); - } - // Handle tuple tangent type. - // Add adjoints for every tuple element that has a tangent space. - if (tupleTanTy.is()) { - assert(adjValues.size() > 1); - addAdjointValue(bb, dti->getOperand(), - makeAggregateAdjointValue(tupleTanTy, adjValues), - dti->getLoc()); - } - // Handle non-tuple tangent type. - // Add adjoint for the single tuple element that has a tangent space. - else { - assert(adjValues.size() == 1); - addAdjointValue(bb, dti->getOperand(), adjValues.front(), dti->getLoc()); + // Check the `destructure_tuple` operand's value tangent category. + switch (getTangentValueCategory(dti->getOperand())) { + case SILValueCategory::Object: { + SmallVector adjValues; + for (auto origElt : dti->getResults()) { + // Skip non-`Differentiable` tuple elements. + if (!getTangentSpace(remapType(origElt->getType()).getASTType())) + continue; + adjValues.push_back(getAdjointValue(bb, origElt)); + } + // Handle tuple tangent type. + // Add adjoints for every tuple element that has a tangent space. + if (tupleTanTy.is()) { + assert(adjValues.size() > 1); + addAdjointValue(bb, dti->getOperand(), + makeAggregateAdjointValue(tupleTanTy, adjValues), loc); + } + // Handle non-tuple tangent type. + // Add adjoint for the single tuple element that has a tangent space. + else { + assert(adjValues.size() == 1); + addAdjointValue(bb, dti->getOperand(), adjValues.front(), loc); + } + break; + } + case SILValueCategory::Address: { + auto adjBuf = getAdjointBuffer(bb, dti->getOperand()); + unsigned adjIndex = 0; + for (auto origElt : dti->getResults()) { + // Skip non-`Differentiable` tuple elements. + if (!getTangentSpace(remapType(origElt->getType()).getASTType())) + continue; + // Handle tuple tangent type. + // Add adjoints for every tuple element that has a tangent space. + if (tupleTanTy.is()) { + auto adjEltBuf = getAdjointBuffer(bb, origElt); + auto adjBufElt = + builder.createTupleElementAddr(loc, adjBuf, adjIndex); + accumulateIndirect(adjBufElt, adjEltBuf, loc); + } + // Handle non-tuple tangent type. + // Add adjoint for the single tuple element that has a tangent space. + else { + auto adjEltBuf = getAdjointBuffer(bb, origElt); + addToAdjointBuffer(bb, dti->getOperand(), adjEltBuf, loc); + } + ++adjIndex; + } + break; + } } } diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index dc0d915148e20..1beeed3c76f13 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -744,6 +744,8 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { pattern, tanType, TypeExpansionContext::minimal()); ParameterConvention conv; switch (origResConv) { + case ResultConvention::Unowned: + case ResultConvention::UnownedInnerPointer: case ResultConvention::Owned: case ResultConvention::Autoreleased: if (tl.isAddressOnly()) { @@ -753,10 +755,6 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { : ParameterConvention::Direct_Guaranteed; } break; - case ResultConvention::Unowned: - case ResultConvention::UnownedInnerPointer: - conv = ParameterConvention::Direct_Unowned; - break; case ResultConvention::Indirect: conv = ParameterConvention::Indirect_In_Guaranteed; break; diff --git a/test/AutoDiff/validation-test/optional-property.swift b/test/AutoDiff/validation-test/optional-property.swift new file mode 100644 index 0000000000000..7a8b150728e44 --- /dev/null +++ b/test/AutoDiff/validation-test/optional-property.swift @@ -0,0 +1,207 @@ +// RUN: %target-run-simple-swift +// RUN: %target-swift-emit-sil -Xllvm -debug-only=differentiation -o /dev/null 2>&1 %s | %FileCheck %s +// REQUIRES: executable_test + +// Test differentiation of `Optional` properties. + +import DifferentiationUnittest +import StdlibUnittest + +var OptionalTests = TestSuite("OptionalPropertyDifferentiation") + +// Test `Optional` struct stored properties. + +struct Struct: Differentiable { + var stored: Float + var optional: Float? + + @differentiable + func method() -> Float { + let s: Struct + do { + let tmp = Struct(stored: stored, optional: optional) + let tuple = (tmp, tmp) + s = tuple.0 + } + if let x = s.optional { + return x * s.stored + } + return s.stored + } +} + +// Check active SIL instructions in representative original functions. +// This tests SIL instruction coverage of derivative function cloners (e.g. PullbackCloner). + +// CHECK-LABEL: [AD] Activity info for ${{.*}}Struct{{.*}}method{{.*}} at (parameters=(0) results=(0)) +// CHECK: [ACTIVE] {{.*}} struct_extract {{%.*}} : $Struct, #Struct.stored +// CHECK: [ACTIVE] {{.*}} struct_extract {{%.*}} : $Struct, #Struct.optional +// CHECK: [ACTIVE] {{.*}} tuple ({{%.*}} : $Struct, {{%.*}} : $Struct) +// CHECK: [ACTIVE] {{.*}} destructure_tuple {{%.*}} : $(Struct, Struct) +// CHECK: [ACTIVE] {{.*}} struct_element_addr {{%.*}} : $*Struct, #Struct.optional +// CHECK: [ACTIVE] {{.*}} struct_element_addr {{%.*}} : $*Struct, #Struct.stored +// CHECK-LABEL: End activity info for ${{.*}}Struct{{.*}}method{{.*}} at (parameters=(0) results=(0)) + +// CHECK-LABEL: [AD] Activity info for $s4null6StructV6stored8optionalACSf_SfSgtcfC at (parameters=(0 1) results=(0)) +// CHECK: [ACTIVE] {{%.*}} struct $Struct ({{%.*}} : $Float, {{%.*}} : $Optional) +// CHECK-LABEL: End activity info for $s4null6StructV6stored8optionalACSf_SfSgtcfC at (parameters=(0 1) results=(0)) + +struct StructTracked: Differentiable { + var stored: NonresilientTracked + var optional: NonresilientTracked? + + @differentiable + func method() -> NonresilientTracked { + let s: StructTracked + do { + let tmp = StructTracked(stored: stored, optional: optional) + let tuple = (tmp, tmp) + s = tuple.0 + } + if let x = s.optional { + return x * s.stored + } + return s.stored + } +} + +struct StructGeneric: Differentiable { + var stored: T + var optional: T? + + @differentiable + func method() -> T { + let s: StructGeneric + do { + let tmp = StructGeneric(stored: stored, optional: optional) + let tuple = (tmp, tmp) + s = tuple.0 + } + if let x = s.optional { + return x + } + return s.stored + } +} + +OptionalTests.test("Optional struct stored properties") { + expectEqual( + valueWithGradient(at: Struct(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: Struct(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: StructTracked(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: StructTracked(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: StructGeneric(stored: 3, optional: 4), in: { $0.method() }), + (4, .init(stored: 0, optional: .init(1)))) + expectEqual( + valueWithGradient(at: StructGeneric(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) +} + +// Test `Optional` class stored properties. + +struct Class: Differentiable { + var stored: Float + var optional: Float? + + init(stored: Float, optional: Float?) { + self.stored = stored + self.optional = optional + } + + @differentiable + func method() -> Float { + let c: Class + do { + let tmp = Class(stored: stored, optional: optional) + let tuple = (tmp, tmp) + c = tuple.0 + } + if let x = c.optional { + return x * c.stored + } + return c.stored + } +} + +struct ClassTracked: Differentiable { + var stored: NonresilientTracked + var optional: NonresilientTracked? + + init(stored: NonresilientTracked, optional: NonresilientTracked?) { + self.stored = stored + self.optional = optional + } + + @differentiable + func method() -> NonresilientTracked { + let c: ClassTracked + do { + let tmp = ClassTracked(stored: stored, optional: optional) + let tuple = (tmp, tmp) + c = tuple.0 + } + if let x = c.optional { + return x * c.stored + } + return c.stored + } +} + +struct ClassGeneric: Differentiable { + var stored: T + var optional: T? + + init(stored: T, optional: T?) { + self.stored = stored + self.optional = optional + } + + @differentiable + func method() -> T { + let c: ClassGeneric + do { + let tmp = ClassGeneric(stored: stored, optional: optional) + let tuple = (tmp, tmp) + c = tuple.0 + } + if let x = c.optional { + return x + } + return c.stored + } +} + +OptionalTests.test("Optional class stored properties") { + expectEqual( + valueWithGradient(at: Class(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: Class(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: ClassTracked(stored: 3, optional: 4), in: { $0.method() }), + (12, .init(stored: 4, optional: .init(3)))) + expectEqual( + valueWithGradient(at: ClassTracked(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) + + expectEqual( + valueWithGradient(at: ClassGeneric>(stored: 3, optional: 4), in: { $0.method() }), + (4, .init(stored: 0, optional: .init(1)))) + expectEqual( + valueWithGradient(at: ClassGeneric>(stored: 3, optional: nil), in: { $0.method() }), + (3, .init(stored: 1, optional: .init(0)))) +} + +runAllTests() diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift index 455fa091e9e67..09aa84d587da2 100644 --- a/test/AutoDiff/validation-test/optional.swift +++ b/test/AutoDiff/validation-test/optional.swift @@ -1,6 +1,8 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test +// Test differentiation of `Optional` values and operations. + import DifferentiationUnittest import StdlibUnittest @@ -10,7 +12,6 @@ var OptionalTests = TestSuite("OptionalDifferentiation") // Basic tests. //===----------------------------------------------------------------------===// - // TODO(TF-433): operator `??` lowers to an active `try_apply`. /* @differentiable @@ -267,7 +268,7 @@ OptionalTests.test("Switch") { (.init(.init(0.0)), 1.0)) } -OptionalTests.test("Var1") { +OptionalTests.test("Optional binding: if let") { @differentiable func optional_var1(_ maybeX: Float?) -> Float { var maybeX = maybeX @@ -393,7 +394,7 @@ OptionalTests.test("Var1") { (.init(.init(0.0)), 1.0)) } -OptionalTests.test("Var2") { +OptionalTests.test("Optional binding: if var") { @differentiable func optional_var2(_ maybeX: Float?) -> Float { if var x = maybeX { From 7c5bb7d819e1fb5a0fb241ea94f073b01c06de7a Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Mon, 24 Aug 2020 12:02:32 -0700 Subject: [PATCH 294/663] Update the master-rebranch scheme to include: * swift-argument-parser * swift-driver * yams --- utils/update_checkout/update-checkout-config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index f70405f4c1d52..eef6fe075ec74 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -316,6 +316,8 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "master", + "swift-argument-parser": "0.0.6", + "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", "swift-corelibs-xctest": "master", @@ -325,6 +327,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-65-1", + "yams": "3.0.1", "cmake": "v3.16.5", "indexstore-db": "master", "sourcekit-lsp": "master", From 6467827add8ef80fa9deae48158b0ff489cdaa1e Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Mon, 24 Aug 2020 15:29:15 -0400 Subject: [PATCH 295/663] [Runtime] Fix memory ordering on two loads in ConcurrentReadableHashMap. --- include/swift/Runtime/Concurrent.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 099b8a3fa560f..10269653284df 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -684,7 +684,7 @@ template struct ConcurrentReadableHashMap { /// Free all the arrays in the free lists if there are no active readers. If /// there are active readers, do nothing. void deallocateFreeListIfSafe() { - if (ReaderCount.load(std::memory_order_relaxed) == 0) + if (ReaderCount.load(std::memory_order_acquire) == 0) deallocateFreeList(); } @@ -857,7 +857,7 @@ template struct ConcurrentReadableHashMap { ElemTy *elements2; do { elements = Elements.load(std::memory_order_acquire); - indices = Indices.load(SWIFT_MEMORY_ORDER_CONSUME); + indices = Indices.load(std::memory_order_acquire); elementCount = ElementCount.load(std::memory_order_acquire); elements2 = Elements.load(std::memory_order_acquire); } while (elements != elements2); From b9c899a3906c21468fb9e15f4f8f5cdf0b31831c Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Mon, 24 Aug 2020 12:56:59 -0700 Subject: [PATCH 296/663] [Package] Fix passing -gline-tables-only when building. We should do regardless of whether we run the tests or not. Also, clarify a comment while I'm here. --- utils/build-presets.ini | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 397b2661498cb..ffea7fcaf8fcc 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1234,10 +1234,15 @@ verbose-build build-ninja build-swift-stdlib-unittest-extra -# When producing a package, don't copy the Swift Resource/ directory. -# This is mainly a space optimization. +# When building for an Xcode toolchain, don't copy the Swift Resource/ directory +# into the LLDB.framework. LLDB.framework will be installed alongside a Swift +# compiler, so LLDB should use its resource directory directly. +# Also, to reduce the size of the final toolchain, limit debug info to be +# line-tables only. extra-cmake-options= -DLLDB_FRAMEWORK_COPY_SWIFT_RESOURCES=0 + -DCMAKE_C_FLAGS="-gline-tables-only" + -DCMAKE_CXX_FLAGS="-gline-tables-only" install-llvm install-swift @@ -1372,10 +1377,6 @@ skip-test-swiftsyntax skip-test-skstresstester skip-test-swiftevolve -extra-cmake-options= - -DCMAKE_C_FLAGS="-gline-tables-only" - -DCMAKE_CXX_FLAGS="-gline-tables-only" - # macOS package with out test [preset: buildbot_osx_package,no_test] mixin-preset= From bafa8bea632cb4c0eb8250efaa36906f7113ef4c Mon Sep 17 00:00:00 2001 From: David Ungar Date: Mon, 24 Aug 2020 14:03:29 -0700 Subject: [PATCH 297/663] Reworded warning. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11da346e95932..b07f047daba6a 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,8 @@ Please make sure you use Python 2.x. Python 3.x is not supported currently. To build for macOS, you need [Xcode 12 beta 3](https://developer.apple.com/xcode/resources/). The required version of Xcode changes frequently, and is often a beta release. Check this document or the host information on for the -current required version. The path name for the Xcode app must not include any spaces. +current required version. Recently (as of 8-22-20), we have seen a bug that causes the build to fail +if the Xcode app path includes any spaces. You will also need [CMake](https://cmake.org) and [Ninja](https://ninja-build.org), which can be installed via a package manager: From e9b9b50062151c708e2b588fd83b0e64f56563dc Mon Sep 17 00:00:00 2001 From: David Ungar Date: Mon, 24 Aug 2020 14:05:12 -0700 Subject: [PATCH 298/663] Jira link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b07f047daba6a..c6725688b7934 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ To build for macOS, you need [Xcode 12 beta 3](https://developer.apple.com/xcode The required version of Xcode changes frequently, and is often a beta release. Check this document or the host information on for the current required version. Recently (as of 8-22-20), we have seen a bug that causes the build to fail -if the Xcode app path includes any spaces. +if the Xcode app path includes any spaces. (See https://bugs.swift.org/browse/SR-13441 .) You will also need [CMake](https://cmake.org) and [Ninja](https://ninja-build.org), which can be installed via a package manager: From d9fdce51fc1c61c2f6e3728c6370d983b9366caf Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 24 Aug 2020 12:19:14 -0700 Subject: [PATCH 299/663] [ownership] When computing usesNotContainedWithinLifetime make sure the error is only a use not in lifetime error. Otherwise, we can return true in cases where we do not have a proper linear lifetime which can occur in the presence of destructures. --- lib/SIL/Verifier/LinearLifetimeChecker.cpp | 11 ++- test/SILOptimizer/semantic-arc-opts.sil | 88 ++++++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/lib/SIL/Verifier/LinearLifetimeChecker.cpp b/lib/SIL/Verifier/LinearLifetimeChecker.cpp index ee5bdf839537a..ebc26a66c9adc 100644 --- a/lib/SIL/Verifier/LinearLifetimeChecker.cpp +++ b/lib/SIL/Verifier/LinearLifetimeChecker.cpp @@ -682,7 +682,6 @@ bool LinearLifetimeChecker::validateLifetime( bool LinearLifetimeChecker::usesNotContainedWithinLifetime( SILValue value, ArrayRef consumingUses, ArrayRef usesToTest) { - auto errorBehavior = ErrorBehaviorKind( ErrorBehaviorKind::ReturnFalse | ErrorBehaviorKind::StoreNonConsumingUsesOutsideLifetime); @@ -707,7 +706,13 @@ bool LinearLifetimeChecker::usesNotContainedWithinLifetime( assert(numFoundUses == uniqueUsers.size()); #endif - // Return true if we /did/ found an error and when emitting that error, we + // If we found any error except for uses outside of our lifetime, bail. + if (error.getFoundLeak() || error.getFoundOverConsume() || + error.getFoundUseAfterFree()) + return false; + + // Return true if we /did/ find an error and when emitting that error, we // found /all/ uses we were looking for. - return error.getFoundError() && numFoundUses == usesToTest.size(); + return error.getFoundUseOutsideOfLifetime() && + numFoundUses == usesToTest.size(); } diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil index ac0de9fae5479..1b79ff3e34775 100644 --- a/test/SILOptimizer/semantic-arc-opts.sil +++ b/test/SILOptimizer/semantic-arc-opts.sil @@ -20,12 +20,19 @@ sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> () sil @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject sil @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever +sil @inout_user : $@convention(thin) (@inout FakeOptional) -> () struct NativeObjectPair { var obj1 : Builtin.NativeObject var obj2 : Builtin.NativeObject } +struct FakeOptionalNativeObjectPairPair { + var pair1 : FakeOptional + var pair2 : FakeOptional +} +sil @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + sil @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair protocol MyFakeAnyObject : Klass { @@ -2639,3 +2646,84 @@ bb6: inject_enum_addr %0 : $*FakeOptional, #FakeOptional.none!enumelt br bb5 } + +// CHECK-LABEL: sil [ossa] @destructure_with_differing_lifetimes_inout_1 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'destructure_with_differing_lifetimes_inout_1' +sil [ossa] @destructure_with_differing_lifetimes_inout_1 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +bb0(%0 : $*FakeOptionalNativeObjectPairPair): + %0a = struct_element_addr %0 : $*FakeOptionalNativeObjectPairPair, #FakeOptionalNativeObjectPairPair.pair1 + %1 = load [copy] %0a : $*FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, default bb2 + +bb2(%2 : @owned $FakeOptional): + destroy_value %2 : $FakeOptional + br bbEnd + +bb1(%3 : @owned $NativeObjectPair): + (%3a, %3b) = destructure_struct %3 : $NativeObjectPair + cond_br undef, bb1a, bb1b + +bb1a: + destroy_value %3a : $Builtin.NativeObject + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bb1b: + destroy_value %3a : $Builtin.NativeObject + %f = function_ref @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + apply %f(%0) : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bbEnd: + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @destructure_with_differing_lifetimes_inout_2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'destructure_with_differing_lifetimes_inout_2' +sil [ossa] @destructure_with_differing_lifetimes_inout_2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { +bb0(%0 : $*FakeOptionalNativeObjectPairPair): + %0a = struct_element_addr %0 : $*FakeOptionalNativeObjectPairPair, #FakeOptionalNativeObjectPairPair.pair1 + %1 = load [copy] %0a : $*FakeOptional + switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, default bb2 + +bb2(%2 : @owned $FakeOptional): + destroy_value %2 : $FakeOptional + br bbEnd + +bb1(%3 : @owned $NativeObjectPair): + (%3a, %3b) = destructure_struct %3 : $NativeObjectPair + cond_br undef, bb1a, bb1b + +bb1a: + destroy_value %3a : $Builtin.NativeObject + br bb1ab + +bb1ab: + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bb1b: + destroy_value %3a : $Builtin.NativeObject + %f = function_ref @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + apply %f(%0) : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () + cond_br undef, bb1ba, bb1bb + +bb1ba: + br bb1baEnd + +bb1bb: + br bb1baEnd + +bb1baEnd: + destroy_value %3b : $Builtin.NativeObject + br bbEnd + +bbEnd: + %9999 = tuple() + return %9999 : $() +} + From c9b316433a36270b60c05f4d105305675b744fba Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 24 Aug 2020 16:04:56 -0700 Subject: [PATCH 300/663] Correct the DeclContext Used For 'super.init()' Synthesis When a subclass inherits from a superclass that declares a no-args desginated initializer and no other visible inits, the subclass may elide calls to 'super.init()'. The way this was enforced was by looking into the superclass *from the subclass' init*, not from the subclass. This ensured that not only would we get results for initializers, we'd get results for initializers that were actually _callable_ from the subclass. The changes in apple/swift#33515 accidentally swapped the decl context here, which caused this lookup to start returning additional results. In that case, we consider it ambiguous as to which designated initializer we should synthesize, and so we bail. The net result is DI errors where there previously were none. Let's put this back in order. rdar://67560590, rdar://67686660, rdar://67690116, SR-13427 --- lib/Sema/TypeCheckStmt.cpp | 6 ++--- .../OtherModule.swift | 11 +++++++++ .../definite_init_cross_module.swift | 24 +++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 7d3666a6205f8..102b11d5fed94 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1764,9 +1764,9 @@ static bool checkSuperInit(ConstructorDecl *fromCtor, NLOptions subOptions = NL_QualifiedDefault | NL_KnownNonCascadingDependency; SmallVector lookupResults; - dc->lookupQualified(superclassDecl, - DeclNameRef::createConstructor(), - subOptions, lookupResults); + fromCtor->lookupQualified(superclassDecl, + DeclNameRef::createConstructor(), + subOptions, lookupResults); for (auto decl : lookupResults) { auto superclassCtor = dyn_cast(decl); diff --git a/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift b/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift index 3e449b357336c..e3568a71bdc25 100644 --- a/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift +++ b/test/SILOptimizer/Inputs/definite_init_cross_module/OtherModule.swift @@ -41,3 +41,14 @@ public struct Empty { public struct GenericEmpty { public init() {} } + +open class VisibleNoArgsDesignatedInit { + var x: Float + public init() { x = 0.0 } + + // Add some designated inits the subclass cannot see. + private init(x: Float) { self.x = x } + fileprivate init(y: Float) { self.x = y } + internal init(z: Float) { self.x = z } +} + diff --git a/test/SILOptimizer/definite_init_cross_module.swift b/test/SILOptimizer/definite_init_cross_module.swift index 2201cbf12c436..6a7f9debbbd1b 100644 --- a/test/SILOptimizer/definite_init_cross_module.swift +++ b/test/SILOptimizer/definite_init_cross_module.swift @@ -254,3 +254,27 @@ extension GenericEmpty { init(xx: Double) { } // expected-error {{'self.init' isn't called on all paths before returning from initializer}} } + +class AcceptsVisibleNoArgsDesignatedInit: VisibleNoArgsDesignatedInit { + var y: Float + init(y: Float) { + self.y = y + // no error + } +} + +open class InModuleVisibleNoArgsDesignatedInit { + var x: Float + public init() { x = 0.0 } + + // Add a designated init the subclass cannot see. + private init(x: Float) { self.x = x } +} + +class AcceptsInModuleVisibleNoArgsDesignatedInit: InModuleVisibleNoArgsDesignatedInit { + var y: Float + init(y: Float) { + self.y = y + // no error + } +} From ce550f2464ca1a2250424029e4837b821476d031 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 24 Aug 2020 17:16:40 -0400 Subject: [PATCH 301/663] AST: Try harder to preserve type sugar in AbstractGenericSignatureRequest AbstractGenericSignatureRequest tries to minimize the number of GSBs that we spin up by only creating a GSB if the generic parameter and requirement types are canonical. If they're not canonical, it first canonicalizes them, then kicks off a request to compute the canonical signature, and finally, re-applies type sugar. We would do this by building a mapping for re-sugaring generic parameters, however this mapping was only populated for the newly-added generic parameters. If some of the newly-added generic requirements mention the base signature's generic parameters, they would remain canonicalized. Fixes . --- lib/AST/GenericSignatureBuilder.cpp | 13 ++++--------- .../inherited-generic-parameters.swift | 3 +++ test/attr/attr_override.swift | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index b4c97fa21fd1c..bff5a8688291d 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -7430,13 +7430,11 @@ AbstractGenericSignatureRequest::evaluate( if (baseSignature) canBaseSignature = baseSignature->getCanonicalSignature(); - llvm::SmallDenseMap mappedTypeParameters; SmallVector canAddedParameters; canAddedParameters.reserve(addedParameters.size()); for (auto gp : addedParameters) { auto canGP = gp->getCanonicalType()->castTo(); canAddedParameters.push_back(canGP); - mappedTypeParameters[canGP] = Type(gp); } SmallVector canAddedRequirements; @@ -7453,10 +7451,8 @@ AbstractGenericSignatureRequest::evaluate( if (!canSignatureResult || !*canSignatureResult) return GenericSignature(); - // Substitute in the original generic parameters to form a more-sugared - // result closer to what the original request wanted. Note that this - // loses sugar on concrete types, but for abstract signatures that - // shouldn't matter. + // Substitute in the original generic parameters to form the sugared + // result the original request wanted. auto canSignature = *canSignatureResult; SmallVector resugaredParameters; resugaredParameters.reserve(canSignature->getGenericParams().size()); @@ -7474,9 +7470,8 @@ AbstractGenericSignatureRequest::evaluate( auto resugaredReq = req.subst( [&](SubstitutableType *type) { if (auto gp = dyn_cast(type)) { - auto knownGP = mappedTypeParameters.find(gp); - if (knownGP != mappedTypeParameters.end()) - return knownGP->second; + unsigned ordinal = canSignature->getGenericParamOrdinal(gp); + return Type(resugaredParameters[ordinal]); } return Type(type); }, diff --git a/test/ModuleInterface/inherited-generic-parameters.swift b/test/ModuleInterface/inherited-generic-parameters.swift index 1be75a69d7311..ecaebf59237e8 100644 --- a/test/ModuleInterface/inherited-generic-parameters.swift +++ b/test/ModuleInterface/inherited-generic-parameters.swift @@ -19,6 +19,8 @@ public class Base { // CHECK-NEXT: public init(_: A, _: A) public init(_: A, _: A) {} +// CHECK-NEXT: public init(_: C) where C : main.Base + public init(_: C) where C : Base {} // CHECK: } } @@ -27,6 +29,7 @@ public class Derived : Base { // CHECK-NEXT: {{(@objc )?}}deinit // CHECK-NEXT: override public init(x: @escaping (T) -> T) // CHECK-NEXT: override public init(_ argument: A, _ argument: A) +// CHECK-NEXT: override public init(_ argument: C) where C : main.Base // CHECK-NEXT: } } diff --git a/test/attr/attr_override.swift b/test/attr/attr_override.swift index b059d707a578f..e234a294b9e02 100644 --- a/test/attr/attr_override.swift +++ b/test/attr/attr_override.swift @@ -590,7 +590,7 @@ class SR_4206_Base_7 { } class SR_4206_Derived_7: SR_4206_Base_7 { - override func foo1() where T: SR_4206_Protocol_2 {} // expected-error {{overridden method 'foo1' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} + override func foo1() where T: SR_4206_Protocol_2 {} // expected-error {{overridden method 'foo1' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} override func foo2() {} // OK } @@ -627,7 +627,7 @@ class SR_4206_Base_10 { func foo() where T: SR_4206_Protocol_1 {} // expected-note {{overridden declaration is here}} } class SR_4206_Derived_10: SR_4206_Base_10 { - override func foo() where U: SR_4206_Protocol_1 {} // expected-error {{overridden method 'foo' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} + override func foo() where U: SR_4206_Protocol_1 {} // expected-error {{overridden method 'foo' has generic signature which is incompatible with base method's generic signature ; expected generic signature to be }} } // Override with return type specialization From b0208a134f9ae4a0729d8a181f9f84a600f24b2e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 24 Aug 2020 17:28:09 -0400 Subject: [PATCH 302/663] AST: Move getSugaredType() from GenericEnvironment to GenericSignature None of this actually involves archetypes, so it can just be an operation on the GenericSignature itself. --- include/swift/AST/GenericEnvironment.h | 7 ----- include/swift/AST/GenericSignature.h | 9 ++++++- include/swift/AST/PrintOptions.h | 6 ++--- lib/AST/ASTPrinter.cpp | 20 +++++++------- lib/AST/Attr.cpp | 22 +++++++-------- lib/AST/GenericEnvironment.cpp | 21 --------------- lib/AST/GenericSignature.cpp | 21 +++++++++++++-- lib/PrintAsObjC/DeclAndTypePrinter.cpp | 2 +- lib/SIL/IR/SILPrinter.cpp | 37 +++++++++++++++----------- 9 files changed, 74 insertions(+), 71 deletions(-) diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h index 144ed20c6621e..a47067b940fa7 100644 --- a/include/swift/AST/GenericEnvironment.h +++ b/include/swift/AST/GenericEnvironment.h @@ -149,13 +149,6 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final std::pair mapConformanceRefIntoContext(Type conformingType, ProtocolConformanceRef conformance) const; - - /// Get the sugared form of a generic parameter type. - GenericTypeParamType *getSugaredType(GenericTypeParamType *type) const; - - /// Get the sugared form of a type by substituting any - /// generic parameter types by their sugared form. - Type getSugaredType(Type type) const; SubstitutionMap getForwardingSubstitutionMap() const; diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index 6f840022dba9a..3a29d21fbd890 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -397,11 +397,18 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final /// /// then this will return 0 for t_0_0, 1 for t_0_1, and 2 for t_1_0. unsigned getGenericParamOrdinal(GenericTypeParamType *param) const; - + /// Get a substitution map that maps all of the generic signature's /// generic parameters to themselves. SubstitutionMap getIdentitySubstitutionMap() const; + /// Get the sugared form of a generic parameter type. + GenericTypeParamType *getSugaredType(GenericTypeParamType *type) const; + + /// Get the sugared form of a type by substituting any + /// generic parameter types by their sugared form. + Type getSugaredType(Type type) const; + /// Whether this generic signature involves a type variable. bool hasTypeVariable() const; diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 38611e1245b56..abfebaf3ffb48 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -24,7 +24,7 @@ namespace swift { class ASTPrinter; -class GenericEnvironment; +class GenericSignatureImpl; class CanType; class Decl; class Pattern; @@ -423,8 +423,8 @@ struct PrintOptions { /// Replaces the name of private and internal properties of types with '_'. bool OmitNameOfInaccessibleProperties = false; - /// Print dependent types as references into this generic environment. - GenericEnvironment *GenericEnv = nullptr; + /// Use this signature to re-sugar dependent types. + const GenericSignatureImpl *GenericSig = nullptr; /// Print types with alternative names from their canonical names. llvm::DenseMap *AlternativeTypeNames = nullptr; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index de48919eab2b3..40fa7ce4ec248 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -24,7 +24,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/FileUnit.h" -#include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericSignature.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" @@ -2488,14 +2488,14 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { Printer << " = "; // FIXME: An inferred associated type witness type alias may reference // an opaque type, but OpaqueTypeArchetypes are always canonicalized - // so lose type sugar for generic params. Bind the generic environment so - // we can map params back into the generic environment and print them + // so lose type sugar for generic params. Bind the generic signature so + // we can map params back into the generic signature and print them // correctly. // // Remove this when we have a way to represent non-canonical archetypes // preserving sugar. - llvm::SaveAndRestore setGenericEnv(Options.GenericEnv, - decl->getGenericEnvironment()); + llvm::SaveAndRestore setGenericSig( + Options.GenericSig, decl->getGenericSignature().getPointer()); printTypeLoc(TypeLoc(decl->getUnderlyingTypeRepr(), Ty)); printDeclGenericRequirements(decl); } @@ -4319,7 +4319,7 @@ class TypePrinter : public TypeVisitor { Optional subBuffer; PrintOptions subOptions = Options; if (auto substitutions = T->getPatternSubstitutions()) { - subOptions.GenericEnv = nullptr; + subOptions.GenericSig = nullptr; subBuffer.emplace(Printer, subOptions); sub = &*subBuffer; @@ -4411,7 +4411,7 @@ class TypePrinter : public TypeVisitor { // A box layout has its own independent generic environment. Don't try // to print it with the environment's generic params. PrintOptions subOptions = Options; - subOptions.GenericEnv = nullptr; + subOptions.GenericSig = nullptr; TypePrinter sub(Printer, subOptions); // Capture list used here to ensure we don't print anything using `this` @@ -4594,10 +4594,10 @@ class TypePrinter : public TypeVisitor { } } - // When printing SIL types, use a generic environment to map them from + // When printing SIL types, use a generic signature to map them from // canonical types to sugared types. - if (Options.GenericEnv) - T = Options.GenericEnv->getSugaredType(T); + if (Options.GenericSig) + T = Options.GenericSig->getSugaredType(T); } auto Name = T->getName(); diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 69719bfb62ce6..1f2c882a61790 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -590,15 +590,15 @@ static void printDifferentiableAttrArguments( stream << ' '; stream << "where "; std::function getInterfaceType; - if (!original || !original->getGenericEnvironment()) { + if (!original || !original->getGenericSignature()) { getInterfaceType = [](Type Ty) -> Type { return Ty; }; } else { - // Use GenericEnvironment to produce user-friendly + // Use GenericSignature to produce user-friendly // names instead of something like 't_0_0'. - auto *genericEnv = original->getGenericEnvironment(); - assert(genericEnv); + auto genericSig = original->getGenericSignature(); + assert(genericSig); getInterfaceType = [=](Type Ty) -> Type { - return genericEnv->getSugaredType(Ty); + return genericSig->getSugaredType(Ty); }; } interleave(requirementsToPrint, [&](Requirement req) { @@ -933,20 +933,20 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, std::function GetInterfaceType; auto *FnDecl = dyn_cast_or_null(D); - if (!FnDecl || !FnDecl->getGenericEnvironment()) + if (!FnDecl || !FnDecl->getGenericSignature()) GetInterfaceType = [](Type Ty) -> Type { return Ty; }; else { - // Use GenericEnvironment to produce user-friendly + // Use GenericSignature to produce user-friendly // names instead of something like t_0_0. - auto *GenericEnv = FnDecl->getGenericEnvironment(); - assert(GenericEnv); + auto GenericSig = FnDecl->getGenericSignature(); + assert(GenericSig); GetInterfaceType = [=](Type Ty) -> Type { - return GenericEnv->getSugaredType(Ty); + return GenericSig->getSugaredType(Ty); }; if (auto sig = attr->getSpecializedSgnature()) { requirementsScratch = sig->requirementsNotSatisfiedBy( - GenericEnv->getGenericSignature()); + GenericSig); requirements = requirementsScratch; } } diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index a5033e16c4c29..8b29c9c85d1ef 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -171,27 +171,6 @@ Type GenericEnvironment::mapTypeIntoContext(GenericTypeParamType *type) const { return result; } -GenericTypeParamType *GenericEnvironment::getSugaredType( - GenericTypeParamType *type) const { - for (auto *sugaredType : getGenericParams()) - if (sugaredType->isEqual(type)) - return sugaredType; - - llvm_unreachable("missing generic parameter"); -} - -Type GenericEnvironment::getSugaredType(Type type) const { - if (!type->hasTypeParameter()) - return type; - - return type.transform([this](Type Ty) -> Type { - if (auto GP = dyn_cast(Ty.getPointer())) { - return Type(getSugaredType(GP)); - } - return Ty; - }); -} - SubstitutionMap GenericEnvironment::getForwardingSubstitutionMap() const { auto genericSig = getGenericSignature(); return SubstitutionMap::get(genericSig, diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index ddb527c8134ec..1f9731635b49f 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -1037,10 +1037,27 @@ SubstitutionMap GenericSignatureImpl::getIdentitySubstitutionMap() const { MakeAbstractConformanceForGenericType()); } +GenericTypeParamType *GenericSignatureImpl::getSugaredType( + GenericTypeParamType *type) const { + unsigned ordinal = getGenericParamOrdinal(type); + return getGenericParams()[ordinal]; +} + +Type GenericSignatureImpl::getSugaredType(Type type) const { + if (!type->hasTypeParameter()) + return type; + + return type.transform([this](Type Ty) -> Type { + if (auto GP = dyn_cast(Ty.getPointer())) { + return Type(getSugaredType(GP)); + } + return Ty; + }); +} + unsigned GenericSignatureImpl::getGenericParamOrdinal( GenericTypeParamType *param) const { - return GenericParamKey(param->getDepth(), param->getIndex()) - .findIndexIn(getGenericParams()); + return GenericParamKey(param).findIndexIn(getGenericParams()); } bool GenericSignatureImpl::hasTypeVariable() const { diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index f2ff6c495431b..4daa75d1faae5 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -1909,7 +1909,7 @@ class DeclAndTypePrinter::Implementation assert(extension->getGenericSignature().getCanonicalSignature() == extendedClass->getGenericSignature().getCanonicalSignature() && "constrained extensions or custom generic parameters?"); - type = extendedClass->getGenericEnvironment()->getSugaredType(type); + type = extendedClass->getGenericSignature()->getSugaredType(type); decl = type->getDecl(); } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index fe0f2dea86795..52d038ec240a9 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -462,18 +462,20 @@ static void printSILFunctionNameAndType( llvm::DenseMap &sugaredTypeNames) { function->printName(OS); OS << " : $"; - auto genSig = - function->getLoweredFunctionType()->getInvocationGenericSignature(); auto *genEnv = function->getGenericEnvironment(); - // If `genSig` and `genEnv` are both defined, get sugared names of generic + const GenericSignatureImpl *genSig = nullptr; + + // If `genEnv` is defined, get sugared names of generic // parameter types for printing. - if (genSig && genEnv) { + if (genEnv) { + genSig = genEnv->getGenericSignature().getPointer(); + llvm::DenseSet usedNames; llvm::SmallString<16> disambiguatedNameBuf; unsigned disambiguatedNameCounter = 1; for (auto *paramTy : genSig->getGenericParams()) { // Get a uniqued sugared name for the generic parameter type. - auto sugaredTy = genEnv->getSugaredType(paramTy); + auto sugaredTy = genEnv->getGenericSignature()->getSugaredType(paramTy); Identifier name = sugaredTy->getName(); while (!usedNames.insert(name).second) { disambiguatedNameBuf.clear(); @@ -495,7 +497,7 @@ static void printSILFunctionNameAndType( } } auto printOptions = PrintOptions::printSIL(); - printOptions.GenericEnv = genEnv; + printOptions.GenericSig = genSig; printOptions.AlternativeTypeNames = sugaredTypeNames.empty() ? nullptr : &sugaredTypeNames; function->getLoweredFunctionType()->print(OS, printOptions); @@ -3245,8 +3247,9 @@ void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << "[serialized] "; getConformance()->printName(OS, Options); - Options.GenericEnv = - getConformance()->getDeclContext()->getGenericEnvironmentOfContext(); + Options.GenericSig = + getConformance()->getDeclContext()->getGenericSignatureOfContext() + .getPointer(); if (isDeclaration()) { OS << "\n\n"; @@ -3289,7 +3292,7 @@ void SILDefaultWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << getProtocol()->getName() << " {\n"; PrintOptions options = PrintOptions::printSIL(); - options.GenericEnv = Protocol->getGenericEnvironmentOfContext(); + options.GenericSig = Protocol->getGenericSignatureOfContext().getPointer(); for (auto &witness : getEntries()) { witness.print(OS, Verbose, options); @@ -3440,12 +3443,17 @@ void SILSpecializeAttr::print(llvm::raw_ostream &OS) const { OS << "exported: " << exported << ", "; OS << "kind: " << kind << ", "; + auto *genericEnv = getFunction()->getGenericEnvironment(); + GenericSignature genericSig; + if (genericEnv) + genericSig = genericEnv->getGenericSignature(); + ArrayRef requirements; SmallVector requirementsScratch; if (auto specializedSig = getSpecializedSignature()) { - if (auto env = getFunction()->getGenericEnvironment()) { + if (genericSig) { requirementsScratch = specializedSig->requirementsNotSatisfiedBy( - env->getGenericSignature()); + genericSig); requirements = requirementsScratch; } else { requirements = specializedSig->getRequirements(); @@ -3455,19 +3463,18 @@ void SILSpecializeAttr::print(llvm::raw_ostream &OS) const { OS << "where "; SILFunction *F = getFunction(); assert(F); - auto GenericEnv = F->getGenericEnvironment(); interleave(requirements, [&](Requirement req) { - if (!GenericEnv) { + if (!genericSig) { req.print(OS, SubPrinter); return; } // Use GenericEnvironment to produce user-friendly // names instead of something like t_0_0. - auto FirstTy = GenericEnv->getSugaredType(req.getFirstType()); + auto FirstTy = genericSig->getSugaredType(req.getFirstType()); if (req.getKind() != RequirementKind::Layout) { auto SecondTy = - GenericEnv->getSugaredType(req.getSecondType()); + genericSig->getSugaredType(req.getSecondType()); Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); ReqWithDecls.print(OS, SubPrinter); } else { From b93ee4c7d28d3462b8569dedefe162d5c485a7d5 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 24 Aug 2020 19:14:00 -0400 Subject: [PATCH 303/663] AST: Remove some calls to getSugaredType() which are no longer necessary It appears that these were working around . --- lib/AST/Attr.cpp | 49 +++++------------------------------------------- 1 file changed, 5 insertions(+), 44 deletions(-) diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 1f2c882a61790..271cf41d1e8d6 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -589,32 +589,11 @@ static void printDifferentiableAttrArguments( if (!isLeadingClause) stream << ' '; stream << "where "; - std::function getInterfaceType; - if (!original || !original->getGenericSignature()) { - getInterfaceType = [](Type Ty) -> Type { return Ty; }; - } else { - // Use GenericSignature to produce user-friendly - // names instead of something like 't_0_0'. - auto genericSig = original->getGenericSignature(); - assert(genericSig); - getInterfaceType = [=](Type Ty) -> Type { - return genericSig->getSugaredType(Ty); - }; - } interleave(requirementsToPrint, [&](Requirement req) { if (const auto &originalGenSig = original->getGenericSignature()) if (originalGenSig->isRequirementSatisfied(req)) return; - auto FirstTy = getInterfaceType(req.getFirstType()); - if (req.getKind() != RequirementKind::Layout) { - auto SecondTy = getInterfaceType(req.getSecondType()); - Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); - ReqWithDecls.print(stream, Options); - } else { - Requirement ReqWithDecls(req.getKind(), FirstTy, - req.getLayoutConstraint()); - ReqWithDecls.print(stream, Options); - } + req.print(stream, Options); }, [&] { stream << ", "; }); @@ -931,22 +910,13 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, if (auto sig = attr->getSpecializedSgnature()) requirements = sig->getRequirements(); - std::function GetInterfaceType; auto *FnDecl = dyn_cast_or_null(D); - if (!FnDecl || !FnDecl->getGenericSignature()) - GetInterfaceType = [](Type Ty) -> Type { return Ty; }; - else { - // Use GenericSignature to produce user-friendly - // names instead of something like t_0_0. - auto GenericSig = FnDecl->getGenericSignature(); - assert(GenericSig); - GetInterfaceType = [=](Type Ty) -> Type { - return GenericSig->getSugaredType(Ty); - }; + if (FnDecl && FnDecl->getGenericSignature()) { + auto genericSig = FnDecl->getGenericSignature(); if (auto sig = attr->getSpecializedSgnature()) { requirementsScratch = sig->requirementsNotSatisfiedBy( - GenericSig); + genericSig); requirements = requirementsScratch; } } @@ -957,16 +927,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, interleave(requirements, [&](Requirement req) { - auto FirstTy = GetInterfaceType(req.getFirstType()); - if (req.getKind() != RequirementKind::Layout) { - auto SecondTy = GetInterfaceType(req.getSecondType()); - Requirement ReqWithDecls(req.getKind(), FirstTy, SecondTy); - ReqWithDecls.print(Printer, Options); - } else { - Requirement ReqWithDecls(req.getKind(), FirstTy, - req.getLayoutConstraint()); - ReqWithDecls.print(Printer, Options); - } + req.print(Printer, Options); }, [&] { Printer << ", "; }); From 995eb66aa777d80c7fce71dbcd35ab75e71024d9 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 24 Aug 2020 19:15:43 -0400 Subject: [PATCH 304/663] AST: Rename SpecializeAttr::getSpecializedSgnature() --- include/swift/AST/Attr.h | 2 +- lib/AST/Attr.cpp | 4 ++-- lib/SIL/IR/SILFunctionBuilder.cpp | 2 +- lib/Serialization/Serialization.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 25fa621adf0bc..0c67ece50d09f 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -1427,7 +1427,7 @@ class SpecializeAttr : public DeclAttribute { TrailingWhereClause *getTrailingWhereClause() const; - GenericSignature getSpecializedSgnature() const { + GenericSignature getSpecializedSignature() const { return specializedSignature; } diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 271cf41d1e8d6..70a1ec3429409 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -907,14 +907,14 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, Printer << "kind: " << kind << ", "; SmallVector requirementsScratch; ArrayRef requirements; - if (auto sig = attr->getSpecializedSgnature()) + if (auto sig = attr->getSpecializedSignature()) requirements = sig->getRequirements(); auto *FnDecl = dyn_cast_or_null(D); if (FnDecl && FnDecl->getGenericSignature()) { auto genericSig = FnDecl->getGenericSignature(); - if (auto sig = attr->getSpecializedSgnature()) { + if (auto sig = attr->getSpecializedSignature()) { requirementsScratch = sig->requirementsNotSatisfiedBy( genericSig); requirements = requirementsScratch; diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index b56d34ea74d00..0ec7e74dbb4d2 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -54,7 +54,7 @@ void SILFunctionBuilder::addFunctionAttributes( ? SILSpecializeAttr::SpecializationKind::Full : SILSpecializeAttr::SpecializationKind::Partial; F->addSpecializeAttr( - SILSpecializeAttr::create(M, SA->getSpecializedSgnature(), + SILSpecializeAttr::create(M, SA->getSpecializedSignature(), SA->isExported(), kind)); } diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 20179b2876c19..e6b73196c152b 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2356,7 +2356,7 @@ class Serializer::DeclSerializer : public DeclVisitor { S.Out, S.ScratchRecord, abbrCode, (unsigned)SA->isExported(), (unsigned)SA->getSpecializationKind(), - S.addGenericSignatureRef(SA->getSpecializedSgnature())); + S.addGenericSignatureRef(SA->getSpecializedSignature())); return; } From a408fd3038e3e10527b8dea79b0c6c23f75ec42f Mon Sep 17 00:00:00 2001 From: David Ungar Date: Mon, 24 Aug 2020 17:30:32 -0700 Subject: [PATCH 305/663] Better paragraph --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c6725688b7934..cdc20d88f9205 100644 --- a/README.md +++ b/README.md @@ -102,8 +102,9 @@ Please make sure you use Python 2.x. Python 3.x is not supported currently. To build for macOS, you need [Xcode 12 beta 3](https://developer.apple.com/xcode/resources/). The required version of Xcode changes frequently, and is often a beta release. Check this document or the host information on for the -current required version. Recently (as of 8-22-20), we have seen a bug that causes the build to fail -if the Xcode app path includes any spaces. (See https://bugs.swift.org/browse/SR-13441 .) +current required version. + +Swift's build tooling is meant to support spaces in the paths passed to them, but using spaces sometimes tickles bugs in Swift's build scripts or the tools they rely on. For example, https://bugs.swift.org/browse/SR-13441 is caused by a space in the Xcode path used on macOS. If you see Swift's build tooling misbehave due to a space in a path, please report the bug on the Swift bug tracker and then change the path to work around it. You will also need [CMake](https://cmake.org) and [Ninja](https://ninja-build.org), which can be installed via a package manager: From bbe13101a10b70782b02291e0b80aea594a997d5 Mon Sep 17 00:00:00 2001 From: David Ungar Date: Mon, 24 Aug 2020 17:36:32 -0700 Subject: [PATCH 306/663] format --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cdc20d88f9205..c772c53ac4dbb 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,13 @@ The required version of Xcode changes frequently, and is often a beta release. Check this document or the host information on for the current required version. -Swift's build tooling is meant to support spaces in the paths passed to them, but using spaces sometimes tickles bugs in Swift's build scripts or the tools they rely on. For example, https://bugs.swift.org/browse/SR-13441 is caused by a space in the Xcode path used on macOS. If you see Swift's build tooling misbehave due to a space in a path, please report the bug on the Swift bug tracker and then change the path to work around it. +Swift's build tooling is meant to support spaces in the paths passed to them, +but using spaces sometimes tickles bugs in Swift's build scripts or the tools +they rely on. For example, [SR-13441](https://bugs.swift.org/browse/SR-13441) +is caused by a space in the Xcode path used on macOS. If you see Swift's build +tooling misbehave due to a space in a path, please +[report the bug on the Swift bug tracker](https://swift.org/contributing/#reporting-bugs) +and then change the path to work around it. You will also need [CMake](https://cmake.org) and [Ninja](https://ninja-build.org), which can be installed via a package manager: From 76da9a064adfb48c321e490968e845d020f14e6a Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Mon, 24 Aug 2020 17:53:25 -0700 Subject: [PATCH 307/663] Use defined(_POSIX_THREADS) to detect pthread support (#33609) Co-authored-by: Ben Rimmington --- include/swift/Runtime/Mutex.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/swift/Runtime/Mutex.h b/include/swift/Runtime/Mutex.h index 019bd5b3b913a..8fe3c43140e45 100644 --- a/include/swift/Runtime/Mutex.h +++ b/include/swift/Runtime/Mutex.h @@ -20,7 +20,11 @@ #include -#if (defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)) +#if __has_include() +#include +#endif + +#if defined(_POSIX_THREADS) #include "swift/Runtime/MutexPThread.h" #elif defined(_WIN32) #include "swift/Runtime/MutexWin32.h" From 5c88421ceab4343454e3a51f55b112df9a32896c Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Tue, 23 Jun 2020 18:08:58 -0700 Subject: [PATCH 308/663] Update swift-argument-parser checkout to 0.3.0 --- utils/update_checkout/update-checkout-config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index eef6fe075ec74..d499ace4e53f5 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -63,7 +63,7 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "master", - "swift-argument-parser": "0.0.6", + "swift-argument-parser": "0.3.0", "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", @@ -93,7 +93,7 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "master", - "swift-argument-parser": "0.0.6", + "swift-argument-parser": "0.3.0", "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", @@ -316,7 +316,7 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "master", - "swift-argument-parser": "0.0.6", + "swift-argument-parser": "0.3.0", "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", From 5e3ef645e68f399ae9320ab9def0eabca99b73e6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 24 Aug 2020 22:49:22 -0400 Subject: [PATCH 309/663] AST: Fix ASTScopeLookup crash if a PatternBindingEntry's context is not a PatternBindingInitializer The function builder transform creates pattern bindings parented in other DeclContexts. If those pattern binding initializer expressions in turn contain multi-statement closures, we will try to perform unqualified lookups from those contexts when we get around to type checking the closure body. Change some unconditional casts to conditional casts in ASTScope lookup, to handle this case. The casts are only performed while checking if the initializer context is part of a 'lazy' property, which doesn't apply here. Fixes . --- lib/AST/ASTScopeLookup.cpp | 4 ++-- .../rdar67239650.swift | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 validation-test/compiler_crashers_2_fixed/rdar67239650.swift diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 250f2ad6c0678..7896e009534a2 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -519,7 +519,7 @@ bool BraceStmtScope::lookupLocalsOrMembers(ArrayRef, bool PatternEntryInitializerScope::lookupLocalsOrMembers( ArrayRef, DeclConsumer consumer) const { // 'self' is available within the pattern initializer of a 'lazy' variable. - auto *initContext = cast_or_null( + auto *initContext = dyn_cast_or_null( decl->getInitContext(0)); if (initContext) { if (auto *selfParam = initContext->getImplicitSelfDecl()) { @@ -816,7 +816,7 @@ Optional ClosureBodyScope::resolveIsCascadingUseForThisScope( Optional PatternEntryInitializerScope::resolveIsCascadingUseForThisScope( Optional isCascadingUse) const { auto *const initContext = getPatternEntry().getInitContext(); - auto *PBI = cast_or_null(initContext); + auto *PBI = dyn_cast_or_null(initContext); auto *isd = PBI ? PBI->getImplicitSelfDecl() : nullptr; // 'self' is available within the pattern initializer of a 'lazy' variable. diff --git a/validation-test/compiler_crashers_2_fixed/rdar67239650.swift b/validation-test/compiler_crashers_2_fixed/rdar67239650.swift new file mode 100644 index 0000000000000..5ec036b8b61cf --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar67239650.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend -typecheck %s + +@_functionBuilder +struct SillyBuilder { + static func buildBlock() -> () {} +} + +struct SillyStruct { + init(@SillyBuilder _: () -> ()) {} +} + +struct UsesSillyStruct { + var x: Int = 0 + + func foo() { + SillyStruct { + let fn = { + if true { + _ = x + } + } + } + } +} From b4fb7d019a3eefd7fe0f51430fa6fa98afe95fc7 Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Tue, 25 Aug 2020 14:15:03 +1000 Subject: [PATCH 310/663] [IDE] Skip visiting constructor references when the decl is unknown Have left in an assert since it would be nice to get a test case for when this actually occurs. Resolves rdar://67412430 --- lib/IDE/SourceEntityWalker.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index 6f6f08e9daf27..dd494e03cad25 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -715,6 +715,12 @@ passReference(ValueDecl *D, Type Ty, SourceLoc BaseNameLoc, SourceRange Range, } } + if (D == nullptr) { + // FIXME: When does this happen? + assert(false && "unhandled reference"); + return true; + } + CharSourceRange CharRange = Lexer::getCharSourceRangeFromSourceRange(D->getASTContext().SourceMgr, Range); From b1c0bd3096cbf0a3e2b26165c96ac421f68f922f Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Mon, 24 Aug 2020 21:21:11 -0700 Subject: [PATCH 311/663] Minor cleanup in ARCSequenceOpts (#33578) * Remove NewInsts from ARCSequenceOpts * Remove more instances of InsertPts * Address comments from #33504 * Make bottom up loop traversal simpler. Use better apis * Update LoopRegion printer with more info --- .../Analysis/LoopRegionAnalysis.h | 5 +-- lib/SILOptimizer/ARC/ARCRegionState.cpp | 35 +++++-------------- lib/SILOptimizer/ARC/ARCSequenceOptUtils.h | 2 +- lib/SILOptimizer/ARC/ARCSequenceOpts.cpp | 17 ++------- lib/SILOptimizer/ARC/ARCSequenceOpts.h | 8 ++--- .../ARC/GlobalARCSequenceDataflow.cpp | 7 ++-- .../ARC/GlobalLoopARCSequenceDataflow.cpp | 32 ++--------------- lib/SILOptimizer/ARC/RefCountState.cpp | 3 -- lib/SILOptimizer/ARC/RefCountState.h | 24 ++++--------- .../Analysis/LoopRegionAnalysis.cpp | 21 +++++++++-- 10 files changed, 47 insertions(+), 107 deletions(-) diff --git a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h index 285e694723617..4975c4bf09787 100644 --- a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h @@ -726,8 +726,9 @@ class LoopRegion { return getSubregionData().RPONumOfHeaderBlock; } - void dump() const; - void print(llvm::raw_ostream &os, bool insertSpaces = false) const; + void dump(bool isVerbose = false) const; + void print(llvm::raw_ostream &os, bool isShort = false, + bool isVerbose = false) const; void dumpName() const; void printName(llvm::raw_ostream &os) const; diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index f636bbc6f64d4..0f60f59fb34b8 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -235,14 +235,12 @@ bool ARCRegionState::processBlockBottomUp( return NestingDetected; } -// Find the relevant insertion points for the loop region R in its -// successors. Returns true if we succeeded. Returns false if any of the -// non-local successors of the region are not leaking blocks. We currently do -// not handle early exits, but do handle trapping blocks. -static bool getInsertionPtsForLoopRegionExits( +// Returns true if any of the non-local successors of the region are leaking +// blocks. We currently do not handle early exits, but do handle trapping +// blocks. Returns false if otherwise +static bool hasEarlyExits( const LoopRegion *R, LoopRegionFunctionInfo *LRFI, - llvm::DenseMap &RegionStateInfo, - llvm::SmallVectorImpl &InsertPts) { + llvm::DenseMap &RegionStateInfo) { assert(R->isLoop() && "Expected a loop region that is representing a loop"); // Go through all of our non local successors. If any of them cannot be @@ -251,23 +249,10 @@ static bool getInsertionPtsForLoopRegionExits( if (any_of(R->getNonLocalSuccs(), [&](unsigned SuccID) -> bool { return !RegionStateInfo[LRFI->getRegion(SuccID)]->allowsLeaks(); })) { - return false; - } - - // We assume that all of our loops have been canonicalized so that /all/ loop - // exit blocks only have exiting blocks as predecessors. This means that all - // successor regions of any region /cannot/ be a region representing a loop. - for (unsigned SuccID : R->getLocalSuccs()) { - auto *SuccRegion = LRFI->getRegion(SuccID); - assert(SuccRegion->isBlock() && "Loop canonicalization failed?!"); - InsertPts.push_back(&*SuccRegion->getBlock()->begin()); + return true; } - // Sort and unique the insert points so we can put them into - // ImmutablePointerSets. - sortUnique(InsertPts); - - return true; + return false; } bool ARCRegionState::processLoopBottomUp( @@ -276,11 +261,9 @@ bool ARCRegionState::processLoopBottomUp( ImmutablePointerSetFactory &SetFactory) { ARCRegionState *State = RegionStateInfo[R]; - llvm::SmallVector InsertPts; - // Try to lookup insertion points for this region. If when checking for - // insertion points, we find that we have non-leaking early exits, clear state + // If we find that we have non-leaking early exits, clear state // and bail. We do not handle these for now. - if (!getInsertionPtsForLoopRegionExits(R, LRFI, RegionStateInfo, InsertPts)) { + if (hasEarlyExits(R, LRFI, RegionStateInfo)) { clearBottomUpState(); return false; } diff --git a/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h index 9c949da165c5d..b94af73cc1aab 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h +++ b/lib/SILOptimizer/ARC/ARCSequenceOptUtils.h @@ -21,7 +21,7 @@ #include "swift/SIL/SILInstruction.h" namespace swift { - bool isARCSignificantTerminator(TermInst *TI); +bool isARCSignificantTerminator(TermInst *TI); } // end namespace swift #endif diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index 450fc808d88e6..fa0602b04bd4f 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -48,7 +48,7 @@ llvm::cl::opt EnableLoopARC("enable-loop-arc", llvm::cl::init(false)); // This routine takes in the ARCMatchingSet \p MatchSet and adds the increments // and decrements to the delete list. void ARCPairingContext::optimizeMatchingSet( - ARCMatchingSet &MatchSet, llvm::SmallVectorImpl &NewInsts, + ARCMatchingSet &MatchSet, llvm::SmallVectorImpl &DeadInsts) { LLVM_DEBUG(llvm::dbgs() << "**** Optimizing Matching Set ****\n"); // Add the old increments to the delete list. @@ -69,7 +69,6 @@ void ARCPairingContext::optimizeMatchingSet( } bool ARCPairingContext::performMatching( - llvm::SmallVectorImpl &NewInsts, llvm::SmallVectorImpl &DeadInsts) { bool MatchedPair = false; @@ -97,7 +96,7 @@ bool ARCPairingContext::performMatching( for (auto *I : Set.Decrements) DecToIncStateMap.erase(I); - optimizeMatchingSet(Set, NewInsts, DeadInsts); + optimizeMatchingSet(Set, DeadInsts); } } @@ -131,7 +130,6 @@ void LoopARCPairingContext::runOnFunction(SILFunction *F) { bool LoopARCPairingContext::processRegion(const LoopRegion *Region, bool FreezePostDomReleases, bool RecomputePostDomReleases) { - llvm::SmallVector NewInsts; llvm::SmallVector DeadInsts; // We have already summarized all subloops of this loop. Now summarize our @@ -145,16 +143,7 @@ bool LoopARCPairingContext::processRegion(const LoopRegion *Region, do { NestingDetected = Evaluator.runOnLoop(Region, FreezePostDomReleases, RecomputePostDomReleases); - MatchedPair = Context.performMatching(NewInsts, DeadInsts); - - if (!NewInsts.empty()) { - LLVM_DEBUG(llvm::dbgs() << "Adding new interesting insts!\n"); - do { - auto *I = NewInsts.pop_back_val(); - LLVM_DEBUG(llvm::dbgs() << " " << *I); - Evaluator.addInterestingInst(I); - } while (!NewInsts.empty()); - } + MatchedPair = Context.performMatching(DeadInsts); if (!DeadInsts.empty()) { LLVM_DEBUG(llvm::dbgs() << "Removing dead interesting insts!\n"); diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.h b/lib/SILOptimizer/ARC/ARCSequenceOpts.h index 36d7eb57f2548..9be3af2cc3620 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.h +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.h @@ -39,11 +39,9 @@ struct ARCPairingContext { ARCPairingContext(SILFunction &F, RCIdentityFunctionInfo *RCIA) : F(F), DecToIncStateMap(), IncToDecStateMap(), RCIA(RCIA) {} - bool performMatching(llvm::SmallVectorImpl &NewInsts, - llvm::SmallVectorImpl &DeadInsts); + bool performMatching(llvm::SmallVectorImpl &DeadInsts); void optimizeMatchingSet(ARCMatchingSet &MatchSet, - llvm::SmallVectorImpl &NewInsts, llvm::SmallVectorImpl &DeadInsts); }; @@ -68,10 +66,8 @@ struct BlockARCPairingContext { bool NestingDetected = Evaluator.run(FreezePostDomReleases); Evaluator.clear(); - llvm::SmallVector NewInsts; llvm::SmallVector DeadInsts; - bool MatchedPair = Context.performMatching(NewInsts, DeadInsts); - NewInsts.clear(); + bool MatchedPair = Context.performMatching(DeadInsts); while (!DeadInsts.empty()) DeadInsts.pop_back_val()->eraseFromParent(); return NestingDetected && MatchedPair; diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp index a6e725e44b619..5d080626d7a19 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp @@ -118,7 +118,6 @@ bool ARCSequenceDataflowEvaluator::processBBTopDown(ARCBBState &BBState) { void ARCSequenceDataflowEvaluator::mergePredecessors( ARCBBStateInfoHandle &DataHandle) { bool HasAtLeastOnePred = false; - llvm::SmallVector BBThatNeedInsertPts; SILBasicBlock *BB = DataHandle.getBB(); ARCBBState &BBState = DataHandle.getState(); @@ -223,10 +222,8 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( SetFactory); auto II = BB.rbegin(); - if (isa(*II)) { - if (!isARCSignificantTerminator(&cast(*II))) { - II++; - } + if (!isARCSignificantTerminator(&cast(*II))) { + II++; } // For each instruction I in BB visited in reverse... diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp index c090a645eb6bd..46715ddabf139 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp @@ -200,40 +200,14 @@ bool LoopARCSequenceDataflowEvaluator::processLoopBottomUp( bool NestingDetected = false; // For each BB in our post order... - auto Start = R->subregion_begin(), End = R->subregion_end(); - if (Start == End) - return false; - - --End; - while (Start != End) { - unsigned SubregionIndex = *End; + for (unsigned SubregionIndex : R->getReverseSubregions()) { auto *Subregion = LRFI->getRegion(SubregionIndex); auto &SubregionData = getARCState(Subregion); // This will always succeed since we have an entry for each BB in our post // order. - LLVM_DEBUG(llvm::dbgs() << "Processing Subregion#: " << SubregionIndex - << "\n"); - - LLVM_DEBUG(llvm::dbgs() << "Merging Successors!\n"); - mergeSuccessors(Subregion, SubregionData); - - // Then perform the region optimization. - NestingDetected |= SubregionData.processBottomUp( - AA, RCFI, EAFI, LRFI, FreezeOwnedArgEpilogueReleases, IncToDecStateMap, - RegionStateInfo, SetFactory); - --End; - } - - { - unsigned SubregionIndex = *End; - auto *Subregion = LRFI->getRegion(SubregionIndex); - auto &SubregionData = getARCState(Subregion); - - // This will always succeed since we have an entry for each BB in our post - // order. - LLVM_DEBUG(llvm::dbgs() << "Processing Subregion#: " << SubregionIndex - << "\n"); + LLVM_DEBUG(llvm::dbgs() + << "Processing Subregion#: " << SubregionIndex << "\n"); LLVM_DEBUG(llvm::dbgs() << "Merging Successors!\n"); mergeSuccessors(Subregion, SubregionData); diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index 58ef94b453af5..76337390c162f 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -285,9 +285,6 @@ handleRefCountInstMatch(SILInstruction *RefCountInst) { return false; case LatticeState::Decremented: case LatticeState::MightBeUsed: - // Unset InsertPt so we remove retain release pairs instead of - // performing code motion. - LLVM_FALLTHROUGH; case LatticeState::MightBeDecremented: return true; } diff --git a/lib/SILOptimizer/ARC/RefCountState.h b/lib/SILOptimizer/ARC/RefCountState.h index c987c8f477795..c234ce0680327 100644 --- a/lib/SILOptimizer/ARC/RefCountState.h +++ b/lib/SILOptimizer/ARC/RefCountState.h @@ -185,17 +185,13 @@ class BottomUpRefCountState : public RefCountState { bool initWithMutatorInst(ImmutablePointerSet *I, RCIdentityFunctionInfo *RCFI); - /// Update this reference count's state given the instruction \p I. \p - /// InsertPt is the point furthest up the CFG where we can move the currently - /// tracked reference count. + /// Update this reference count's state given the instruction \p I. void updateForSameLoopInst(SILInstruction *I, ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); - /// Update this reference count's state given the instruction \p I. \p - /// InsertPts are the points furthest up the CFG where we can move the - /// currently tracked reference count. + /// Update this reference count's state given the instruction \p I. // /// The main difference in between this routine and update for same loop inst /// is that if we see any decrements on a value, we treat it as being @@ -244,9 +240,7 @@ class BottomUpRefCountState : public RefCountState { bool valueCanBeUsedGivenLatticeState() const; /// Given the current lattice state, if we have seen a use, advance the - /// lattice state. Return true if we do so and false otherwise. \p InsertPt is - /// the location where if \p PotentialUser is a user of this ref count, we - /// would insert a release. + /// lattice state. Return true if we do so and false otherwise. bool handleUser(SILValue RCIdentity, ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); @@ -264,9 +258,7 @@ class BottomUpRefCountState : public RefCountState { bool valueCanBeGuaranteedUsedGivenLatticeState() const; /// Given the current lattice state, if we have seen a use, advance the - /// lattice state. Return true if we do so and false otherwise. \p InsertPt is - /// the location where if \p PotentialUser is a user of this ref count, we - /// would insert a release. + /// lattice state. Return true if we do so and false otherwise. bool handleGuaranteedUser(SILValue RCIdentity, ImmutablePointerSetFactory &SetFactory, @@ -338,17 +330,13 @@ class TopDownRefCountState : public RefCountState { /// Uninitialize the current state. void clear(); - /// Update this reference count's state given the instruction \p I. \p - /// InsertPt is the point furthest up the CFG where we can move the currently - /// tracked reference count. + /// Update this reference count's state given the instruction \p I. void updateForSameLoopInst(SILInstruction *I, ImmutablePointerSetFactory &SetFactory, AliasAnalysis *AA); - /// Update this reference count's state given the instruction \p I. \p - /// InsertPts are the points furthest up the CFG where we can move the - /// currently tracked reference count. + /// Update this reference count's state given the instruction \p I. /// /// The main difference in between this routine and update for same loop inst /// is that if we see any decrements on a value, we treat it as being diff --git a/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp b/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp index ad6a9f10327b5..2050c2d9c9b2d 100644 --- a/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp @@ -45,8 +45,8 @@ LoopRegion::FunctionTy *LoopRegion::getFunction() const { return Ptr.get(); } -void LoopRegion::dump() const { - print(llvm::outs()); +void LoopRegion::dump(bool isVerbose) const { + print(llvm::outs(), false, isVerbose); llvm::outs() << "\n"; } @@ -69,7 +69,8 @@ void LoopRegion::printName(llvm::raw_ostream &os) const { return; } -void LoopRegion::print(llvm::raw_ostream &os, bool isShort) const { +void LoopRegion::print(llvm::raw_ostream &os, bool isShort, + bool isVerbose) const { os << "(region id:" << ID; if (isShort) { os << ")"; @@ -88,6 +89,20 @@ void LoopRegion::print(llvm::raw_ostream &os, bool isShort) const { os << " ucfh:" << (IsUnknownControlFlowEdgeHead? "true " : "false") << " ucft:" << (IsUnknownControlFlowEdgeTail? "true " : "false"); + + if (!isVerbose) { + return; + } + os << "\n"; + if (isBlock()) { + getBlock()->dump(); + } else if (isLoop()) { + getLoop()->dump(); + } else if (isFunction()) { + getFunction()->dump(); + } else { + llvm_unreachable("Unknown region type"); + } } llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &os, LoopRegion &LR) { From 9ead8d57faa1e7290139dc71d46086a66fff35b6 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Tue, 25 Aug 2020 06:03:14 -0700 Subject: [PATCH 312/663] Add a single-threaded stdlib mode, use it for the 'minimal' stdlib (#33437) --- CMakeLists.txt | 4 ---- include/swift/Basic/Lazy.h | 10 ++++++++-- include/swift/Runtime/Mutex.h | 6 ++++-- .../{MutexWASI.h => MutexSingleThreaded.h} | 12 ++++-------- include/swift/Runtime/Once.h | 6 +++++- stdlib/CMakeLists.txt | 12 ++++++++++++ stdlib/cmake/modules/AddSwiftStdlib.cmake | 8 ++++++++ stdlib/public/runtime/CMakeLists.txt | 4 ---- stdlib/public/runtime/Exclusivity.cpp | 9 ++++++++- stdlib/public/runtime/MetadataCache.h | 18 +++++++++++++++--- stdlib/public/runtime/MutexPThread.cpp | 6 +++++- stdlib/public/runtime/Once.cpp | 13 +++++++++++-- stdlib/public/stubs/Stubs.cpp | 4 ++++ stdlib/public/stubs/ThreadLocalStorage.cpp | 14 +++++++++++++- utils/build-presets.ini | 1 + utils/build-script-impl | 2 ++ 16 files changed, 100 insertions(+), 29 deletions(-) rename include/swift/Runtime/{MutexWASI.h => MutexSingleThreaded.h} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b85c876071459..844fcdb251f37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,10 +390,6 @@ option(SWIFT_RUNTIME_ENABLE_LEAK_CHECKER "Should the runtime be built with support for non-thread-safe leak detecting entrypoints" FALSE) -option(SWIFT_STDLIB_USE_NONATOMIC_RC - "Build the standard libraries and overlays with nonatomic reference count operations enabled" - FALSE) - option(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS "Enable runtime function counters and expose the API." FALSE) diff --git a/include/swift/Basic/Lazy.h b/include/swift/Basic/Lazy.h index 521227f4db231..87eecbe295c3c 100644 --- a/include/swift/Basic/Lazy.h +++ b/include/swift/Basic/Lazy.h @@ -14,7 +14,9 @@ #define SWIFT_BASIC_LAZY_H #include -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +// No dependencies on single-threaded environments. +#elif defined(__APPLE__) #include #elif defined(__wasi__) // No pthread on wasi, see https://bugs.swift.org/browse/SR-12097 for more details. @@ -44,7 +46,11 @@ inline void wasi_call_once(int *flag, void *context, void (*func)(void *)) { namespace swift { -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + using OnceToken_t = bool; +# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ + if (!TOKEN) { TOKEN = true; (FUNC)(CONTEXT); } +#elif defined(__APPLE__) using OnceToken_t = dispatch_once_t; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ ::dispatch_once_f(&TOKEN, CONTEXT, FUNC) diff --git a/include/swift/Runtime/Mutex.h b/include/swift/Runtime/Mutex.h index 8fe3c43140e45..aff2005d87514 100644 --- a/include/swift/Runtime/Mutex.h +++ b/include/swift/Runtime/Mutex.h @@ -24,12 +24,14 @@ #include #endif -#if defined(_POSIX_THREADS) +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#include "swift/Runtime/MutexSingleThreaded.h" +#elif defined(_POSIX_THREADS) #include "swift/Runtime/MutexPThread.h" #elif defined(_WIN32) #include "swift/Runtime/MutexWin32.h" #elif defined(__wasi__) -#include "swift/Runtime/MutexWASI.h" +#include "swift/Runtime/MutexSingleThreaded.h" #else #error "Implement equivalent of MutexPThread.h/cpp for your platform." #endif diff --git a/include/swift/Runtime/MutexWASI.h b/include/swift/Runtime/MutexSingleThreaded.h similarity index 82% rename from include/swift/Runtime/MutexWASI.h rename to include/swift/Runtime/MutexSingleThreaded.h index 153a5f87b11dd..4a25e9091b3d5 100644 --- a/include/swift/Runtime/MutexWASI.h +++ b/include/swift/Runtime/MutexSingleThreaded.h @@ -1,4 +1,4 @@ -//===--- MutexWASI.h - -----------------------------------------*- C++ -*-===// +//===--- MutexSingleThreaded.h - --------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -10,16 +10,12 @@ // //===----------------------------------------------------------------------===// // -// No-op implementation of locks for the WebAssembly System Interface. The -// implementation does not need to perform locking, because as of January 2020 -// WebAssembly does not support threads. -// See the current status at https://github.com/WebAssembly/proposals and -// https://github.com/webassembly/threads +// No-op implementation of locks for single-threaded environments. // //===----------------------------------------------------------------------===// -#ifndef SWIFT_RUNTIME_MUTEX_WASI_H -#define SWIFT_RUNTIME_MUTEX_WASI_H +#ifndef SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H +#define SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H namespace swift { diff --git a/include/swift/Runtime/Once.h b/include/swift/Runtime/Once.h index 8a78cddc23c56..f9931edf5b9bf 100644 --- a/include/swift/Runtime/Once.h +++ b/include/swift/Runtime/Once.h @@ -22,7 +22,11 @@ namespace swift { -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +typedef bool swift_once_t; + +#elif defined(__APPLE__) // On OS X and iOS, swift_once_t matches dispatch_once_t. typedef long swift_once_t; diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index 2e82392b6e20a..fab91273b97ec 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -21,6 +21,18 @@ option(SWIFT_RUNTIME_MACHO_NO_DYLD "Build stdlib assuming the runtime environment uses Mach-O but does not support dynamic modules." FALSE) +option(SWIFT_STDLIB_USE_NONATOMIC_RC + "Build the standard libraries and overlays with nonatomic reference count operations enabled" + FALSE) + +option(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + "Build the standard libraries assuming that they will be used in an environment with only a single thread. If set, also forces SWIFT_STDLIB_USE_NONATOMIC_RC to On." + FALSE) + +if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) + set(SWIFT_STDLIB_USE_NONATOMIC_RC TRUE) +endif() + # # End of user-configurable options. # diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 34d5d417d42be..2ce27dc08e0c6 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -306,6 +306,14 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-DSWIFT_RUNTIME_MACHO_NO_DYLD") endif() + if(SWIFT_STDLIB_USE_NONATOMIC_RC) + list(APPEND result "-DSWIFT_STDLIB_USE_NONATOMIC_RC") + endif() + + if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) + list(APPEND result "-DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME") + endif() + set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) endfunction() diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index bb5cfe990cb7e..e29be3ff2033e 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -152,16 +152,12 @@ if(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "LINUX") INSTALL_IN_COMPONENT never_install) endif() -if(SWIFT_STDLIB_USE_NONATOMIC_RC) - set(_RUNTIME_NONATOMIC_FLAGS -DSWIFT_STDLIB_USE_NONATOMIC_RC) -endif() add_swift_target_library(swiftRuntime OBJECT_LIBRARY ${swift_runtime_sources} ${swift_runtime_objc_sources} ${swift_runtime_leaks_sources} C_COMPILE_FLAGS ${swift_runtime_library_compile_flags} - ${_RUNTIME_NONATOMIC_FLAGS} LINK_FLAGS ${swift_runtime_linker_flags} SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} INSTALL_IN_COMPONENT never_install) diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp index 4d8d0d23eea7b..73628b7cdaae4 100644 --- a/stdlib/public/runtime/Exclusivity.cpp +++ b/stdlib/public/runtime/Exclusivity.cpp @@ -250,7 +250,14 @@ class SwiftTLSContext { // Each of these cases should define a function with this prototype: // AccessSets &getAllSets(); -#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +static SwiftTLSContext &getTLSContext() { + static SwiftTLSContext TLSContext; + return TLSContext; +} + +#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC // Use the reserved TSD key if possible. static SwiftTLSContext &getTLSContext() { diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index 6e471273e4702..d6f188f971e3c 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -775,10 +775,22 @@ class MetadataCacheEntryBase using super::asImpl; private: + #ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + using ThreadID = int; + static ThreadID CurrentThreadID() { + return 0; + } + #else + using ThreadID = std::thread::id; + static ThreadID CurrentThreadID() { + return std::this_thread::get_id(); + } + #endif + /// Additional storage that is only ever accessed under the lock. union LockedStorage_t { /// The thread that is allocating the entry. - std::thread::id AllocatingThread; + ThreadID AllocatingThread; /// The completion queue. MetadataCompletionQueueEntry *CompletionQueue; @@ -837,7 +849,7 @@ class MetadataCacheEntryBase MetadataCacheEntryBase() : LockedStorageKind(LSK::AllocatingThread), TrackingInfo(PrivateMetadataTrackingInfo::initial().getRawValue()) { - LockedStorage.AllocatingThread = std::this_thread::get_id(); + LockedStorage.AllocatingThread = CurrentThreadID(); } // Note that having an explicit destructor here is important to make this @@ -850,7 +862,7 @@ class MetadataCacheEntryBase bool isBeingAllocatedByCurrentThread() const { return LockedStorageKind == LSK::AllocatingThread && - LockedStorage.AllocatingThread == std::this_thread::get_id(); + LockedStorage.AllocatingThread == CurrentThreadID(); } /// Given that this thread doesn't own the right to initialize the diff --git a/stdlib/public/runtime/MutexPThread.cpp b/stdlib/public/runtime/MutexPThread.cpp index 92db58226cd09..ac7f93a5a0ed8 100644 --- a/stdlib/public/runtime/MutexPThread.cpp +++ b/stdlib/public/runtime/MutexPThread.cpp @@ -15,7 +15,11 @@ // //===----------------------------------------------------------------------===// -#if !defined(_WIN32) && !defined(__wasi__) +#if __has_include() +#include +#endif + +#if defined(_POSIX_THREADS) && !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) #include "swift/Runtime/Mutex.h" #include "swift/Runtime/Debug.h" diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index 57282590cbd06..1460b0603ef17 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -21,7 +21,11 @@ using namespace swift; -#ifdef __APPLE__ +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +// No dependencies on single-threaded environments. + +#elif defined(__APPLE__) // On macOS and iOS, swift_once is implemented using GCD. // The compiler emits an inline check matching the barrier-free inline fast @@ -48,7 +52,12 @@ static_assert(sizeof(swift_once_t) <= sizeof(void*), /// extent of type swift_once_t. void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), void *context) { -#if defined(__APPLE__) +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + if (! *predicate) { + *predicate = true; + fn(context); + } +#elif defined(__APPLE__) dispatch_once_f(predicate, context, fn); #elif defined(__CYGWIN__) _swift_once_f(predicate, context, fn); diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 949dca892d81f..15338277fb1d2 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -510,5 +510,9 @@ int _swift_stdlib_putc_stderr(int C) { } size_t _swift_stdlib_getHardwareConcurrency() { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return 1; +#else return std::thread::hardware_concurrency(); +#endif } diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 50168f955bc6c..7a335e8e0d144 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -54,7 +54,19 @@ _stdlib_thread_key_create(__swift_thread_key_t * _Nonnull key, #endif -#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +SWIFT_RUNTIME_STDLIB_INTERNAL +void * +_swift_stdlib_threadLocalStorageGet(void) { + static void *value; + if (!value) { + value = _stdlib_createTLS(); + } + return value; +} + +#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC SWIFT_RUNTIME_STDLIB_INTERNAL void * diff --git a/utils/build-presets.ini b/utils/build-presets.ini index ffea7fcaf8fcc..ad2ab73e7893f 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2431,6 +2431,7 @@ build-swift-static-stdlib=1 swift-objc-interop=0 swift-enable-compatibility-overrides=0 swift-runtime-macho-no-dyld=1 +swift-stdlib-single-threaded-runtime=1 [preset: stdlib_S_standalone_minimal_macho_x86_64,build] mixin-preset= diff --git a/utils/build-script-impl b/utils/build-script-impl index 16bf04f3efaf9..09c1893bc6f9a 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -195,6 +195,7 @@ KNOWN_SETTINGS=( swift-objc-interop "" "whether to enable interoperability with Objective-C, default is 1 on Apple platfors, 0 otherwise" swift-enable-compatibility-overrides "1" "whether to support back-deploying compatibility fixes for newer apps running on older runtimes" swift-runtime-macho-no-dyld "0" "whether to build stdlib assuming the runtime environment does not support dynamic modules" + swift-stdlib-single-threaded-runtime "0" "whether to build stdlib as a single-threaded runtime only" ## FREESTANDING Stdlib Options swift-freestanding-sdk "" "which SDK to use when building the FREESTANDING stdlib" @@ -1756,6 +1757,7 @@ for host in "${ALL_HOSTS[@]}"; do -DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}") -DSWIFT_STDLIB_USE_NONATOMIC_RC:BOOL=$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}") -DSWIFT_ENABLE_COMPATIBILITY_OVERRIDES:BOOL=$(true_false "${SWIFT_ENABLE_COMPATIBILITY_OVERRIDES}") + -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME:BOOL=$(true_false "${SWIFT_STDLIB_SINGLE_THREADED_RUNTIME}") -DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS:BOOL=$(true_false "${SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS}") -DSWIFT_RUNTIME_MACHO_NO_DYLD:BOOL=$(true_false "${SWIFT_RUNTIME_MACHO_NO_DYLD}") -DSWIFT_NATIVE_LLVM_TOOLS_PATH:STRING="${native_llvm_tools_path}" From dd9e1cf618228226ad52ce76bc6c92bb0db4b1af Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 25 Aug 2020 10:16:43 -0700 Subject: [PATCH 313/663] [CS] Don't use TMF_GenerateConstraints in simplifyConstraint Adding a new unsolved constraint is redundant, as it's already present in the inactive list. Noticed by inspection. --- lib/Sema/CSSimplify.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1608f19e49155..5ba9345c7c555 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -10657,7 +10657,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { case ConstraintKind::OptionalObject: return simplifyOptionalObjectConstraint(constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::ValueMember: @@ -10669,8 +10669,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { constraint.getMemberUseDC(), constraint.getFunctionRefKind(), /*outerAlternatives=*/{}, - TMF_GenerateConstraints, - constraint.getLocator()); + /*flags*/ None, constraint.getLocator()); case ConstraintKind::ValueWitness: return simplifyValueWitnessConstraint(constraint.getKind(), @@ -10679,20 +10678,20 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { constraint.getSecondType(), constraint.getMemberUseDC(), constraint.getFunctionRefKind(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::Defaultable: return simplifyDefaultableConstraint(constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::DefaultClosureType: return simplifyDefaultClosureTypeConstraint(constraint.getFirstType(), constraint.getSecondType(), constraint.getTypeVariables(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::FunctionInput: @@ -10700,7 +10699,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyFunctionComponentConstraint(constraint.getKind(), constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::Disjunction: @@ -10712,8 +10711,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyOneWayConstraint(constraint.getKind(), constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, - constraint.getLocator()); + /*flags*/ None, constraint.getLocator()); } llvm_unreachable("Unhandled ConstraintKind in switch."); From 6480bfaad2c0e7f2e3b813f9bc2c4de987401c40 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Wed, 12 Aug 2020 11:34:18 -0700 Subject: [PATCH 314/663] [gardening] Move FuzzyStringMatcher to libIDE --- .../swift/IDE}/FuzzyStringMatcher.h | 16 +++++++++------- lib/IDE/CMakeLists.txt | 1 + .../Support => lib/IDE}/FuzzyStringMatcher.cpp | 7 ++++--- tools/SourceKit/lib/Support/CMakeLists.txt | 1 - .../lib/SwiftLang/CodeCompletionOrganizer.cpp | 2 +- .../SourceKit/Support/FuzzyStringMatcherTest.cpp | 4 ++-- 6 files changed, 17 insertions(+), 14 deletions(-) rename {tools/SourceKit/include/SourceKit/Support => include/swift/IDE}/FuzzyStringMatcher.h (83%) rename {tools/SourceKit/lib/Support => lib/IDE}/FuzzyStringMatcher.cpp (99%) diff --git a/tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h b/include/swift/IDE/FuzzyStringMatcher.h similarity index 83% rename from tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h rename to include/swift/IDE/FuzzyStringMatcher.h index cb53e962de0d7..af80647e37c3e 100644 --- a/tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h +++ b/include/swift/IDE/FuzzyStringMatcher.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,14 +10,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H -#define LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H +#ifndef SWIFT_IDE_FUZZYSTRINGMATCHER_H +#define SWIFT_IDE_FUZZYSTRINGMATCHER_H -#include "SourceKit/Core/LLVM.h" +#include "swift/Basic/LLVM.h" #include "llvm/ADT/BitVector.h" #include -namespace SourceKit { +namespace swift { +namespace ide { /// FuzzyStringMatcher compares candidate strings against a pattern /// string using a fuzzy matching algorithm and provides a numerical @@ -49,6 +50,7 @@ class FuzzyStringMatcher { double scoreCandidate(StringRef candidate) const; }; -} // end namespace SourceKit +} // namespace ide +} // namespace swift -#endif // LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H +#endif // SWIFT_IDE_FUZZYSTRINGMATCHER_H diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt index 7348c057ef63a..e7529a25a89d5 100644 --- a/lib/IDE/CMakeLists.txt +++ b/lib/IDE/CMakeLists.txt @@ -7,6 +7,7 @@ add_swift_host_library(swiftIDE STATIC ConformingMethodList.cpp ExprContextAnalysis.cpp Formatting.cpp + FuzzyStringMatcher.cpp Refactoring.cpp ModuleInterfacePrinting.cpp REPLCodeCompletion.cpp diff --git a/tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp b/lib/IDE/FuzzyStringMatcher.cpp similarity index 99% rename from tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp rename to lib/IDE/FuzzyStringMatcher.cpp index 463d541d0d850..d016464691f19 100644 --- a/tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp +++ b/lib/IDE/FuzzyStringMatcher.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,12 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "SourceKit/Support/FuzzyStringMatcher.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "clang/Basic/CharInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" -using namespace SourceKit; +using namespace swift; +using namespace swift::ide; using clang::toUppercase; using clang::toLowercase; using clang::isUppercase; diff --git a/tools/SourceKit/lib/Support/CMakeLists.txt b/tools/SourceKit/lib/Support/CMakeLists.txt index 901720a521069..3b18cc18e98c9 100644 --- a/tools/SourceKit/lib/Support/CMakeLists.txt +++ b/tools/SourceKit/lib/Support/CMakeLists.txt @@ -1,6 +1,5 @@ add_sourcekit_library(SourceKitSupport Concurrency-libdispatch.cpp - FuzzyStringMatcher.cpp Logging.cpp ImmutableTextBuffer.cpp ThreadSafeRefCntPtr.cpp diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index 8ac901da4de3c..a7864e91cc65a 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// #include "CodeCompletionOrganizer.h" -#include "SourceKit/Support/FuzzyStringMatcher.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Module.h" #include "swift/IDE/CodeCompletionResultPrinter.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "swift/Frontend/Frontend.h" #include "swift/Markup/XMLUtils.h" #include "clang/Basic/CharInfo.h" diff --git a/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp b/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp index e0e7e83b4220c..e190933fcd988 100644 --- a/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp +++ b/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "SourceKit/Support/FuzzyStringMatcher.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "gtest/gtest.h" -using FuzzyStringMatcher = SourceKit::FuzzyStringMatcher; +using FuzzyStringMatcher = swift::ide::FuzzyStringMatcher; TEST(FuzzyStringMatcher, BasicMatching) { { From 34de805d7fa0080e5fdad87a5bad06312271c4ad Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Aug 2020 09:52:28 -0700 Subject: [PATCH 315/663] [gardening] Move source text printing alongside other completion methods --- .../swift/IDE/CodeCompletionResultPrinter.h | 3 + lib/IDE/CodeCompletionResultPrinter.cpp | 113 ++++++++++++++++ .../lib/SwiftLang/SwiftCompletion.cpp | 123 +----------------- 3 files changed, 118 insertions(+), 121 deletions(-) diff --git a/include/swift/IDE/CodeCompletionResultPrinter.h b/include/swift/IDE/CodeCompletionResultPrinter.h index 717d6282a4309..05d4cb0f473b7 100644 --- a/include/swift/IDE/CodeCompletionResultPrinter.h +++ b/include/swift/IDE/CodeCompletionResultPrinter.h @@ -34,6 +34,9 @@ void printCodeCompletionResultTypeName( void printCodeCompletionResultTypeNameAnnotated( const CodeCompletionResult &Result, llvm::raw_ostream &OS); +void printCodeCompletionResultSourceText( + const CodeCompletionResult &Result, llvm::raw_ostream &OS); + } // namespace ide } // namespace swift diff --git a/lib/IDE/CodeCompletionResultPrinter.cpp b/lib/IDE/CodeCompletionResultPrinter.cpp index e5c9986ab1fde..7da3932d33191 100644 --- a/lib/IDE/CodeCompletionResultPrinter.cpp +++ b/lib/IDE/CodeCompletionResultPrinter.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "swift/Basic/LLVM.h" +#include "swift/AST/ASTPrinter.h" #include "swift/IDE/CodeCompletionResultPrinter.h" #include "swift/IDE/CodeCompletion.h" #include "swift/Markup/XMLUtils.h" @@ -255,3 +256,115 @@ void swift::ide::printCodeCompletionResultTypeNameAnnotated(const CodeCompletion AnnotatingResultPrinter printer(OS); printer.printTypeName(Result); } + +/// Provide the text for the call parameter, including constructing a typed +/// editor placeholder for it. +static void constructTextForCallParam( + ArrayRef ParamGroup, raw_ostream &OS) { + assert(ParamGroup.front().is(ChunkKind::CallParameterBegin)); + + for (; !ParamGroup.empty(); ParamGroup = ParamGroup.slice(1)) { + auto &C = ParamGroup.front(); + if (C.isAnnotation()) + continue; + if (C.is(ChunkKind::CallParameterInternalName) || + C.is(ChunkKind::CallParameterType) || + C.is(ChunkKind::CallParameterTypeBegin) || + C.is(ChunkKind::CallParameterClosureExpr)) { + break; + } + if (!C.hasText()) + continue; + OS << C.getText(); + } + + SmallString<32> DisplayString; + SmallString<32> TypeString; + SmallString<32> ExpansionTypeString; + + for (auto i = ParamGroup.begin(), e = ParamGroup.end(); i != e; ++i) { + auto &C = *i; + if (C.is(ChunkKind::CallParameterTypeBegin)) { + assert(TypeString.empty()); + auto nestingLevel = C.getNestingLevel(); + ++i; + for (; i != e; ++i) { + if (i->endsPreviousNestedGroup(nestingLevel)) + break; + if (!i->isAnnotation() && i->hasText()) { + TypeString += i->getText(); + DisplayString += i->getText(); + } + } + --i; + continue; + } + if (C.is(ChunkKind::CallParameterClosureType)) { + assert(ExpansionTypeString.empty()); + ExpansionTypeString = C.getText(); + continue; + } + if (C.is(ChunkKind::CallParameterType)) { + assert(TypeString.empty()); + TypeString = C.getText(); + } + if (C.is(ChunkKind::CallParameterClosureExpr)) { + // We have a closure expression, so provide it directly instead of in + // a placeholder. + OS << "{"; + if (!C.getText().empty()) + OS << " " << C.getText(); + OS << "\n" << getCodePlaceholder() << "\n}"; + return; + } + if (C.isAnnotation() || !C.hasText()) + continue; + DisplayString += C.getText(); + } + + StringRef Display = DisplayString.str(); + StringRef Type = TypeString.str(); + StringRef ExpansionType = ExpansionTypeString.str(); + if (ExpansionType.empty()) + ExpansionType = Type; + + OS << "<#T##" << Display; + if (Display == Type && Display == ExpansionType) { + // Short version, display and type are the same. + } else { + OS << "##" << Type; + if (ExpansionType != Type) + OS << "##" << ExpansionType; + } + OS << "#>"; +} + +void swift::ide::printCodeCompletionResultSourceText(const CodeCompletionResult &Result, llvm::raw_ostream &OS) { + auto Chunks = Result.getCompletionString()->getChunks(); + for (size_t i = 0; i < Chunks.size(); ++i) { + auto &C = Chunks[i]; + if (C.is(ChunkKind::BraceStmtWithCursor)) { + OS << " {\n" << getCodePlaceholder() << "\n}"; + continue; + } + if (C.is(ChunkKind::CallParameterBegin)) { + size_t Start = i++; + for (; i < Chunks.size(); ++i) { + if (Chunks[i].endsPreviousNestedGroup(C.getNestingLevel())) + break; + } + constructTextForCallParam(Chunks.slice(Start, i-Start), OS); + --i; + continue; + } + if (C.is(ChunkKind::TypeAnnotationBegin)) { + // Skip type annotation structure. + auto level = C.getNestingLevel(); + do { ++i; } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); + --i; + } + if (!C.isAnnotation() && C.hasText()) { + OS << C.getText(); + } + } +} diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index 0870461fede85..c0ab78cb37825 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -75,9 +75,6 @@ struct SwiftToSourceKitCompletionAdapter { bool legacyLiteralToKeyword, bool annotatedDescription); - static void getResultSourceText(const CodeCompletionString *CCStr, - raw_ostream &OS); - static void getResultAssociatedUSRs(ArrayRef AssocUSRs, raw_ostream &OS); }; @@ -466,7 +463,7 @@ bool SwiftToSourceKitCompletionAdapter::handleResult( unsigned TextBegin = SS.size(); { llvm::raw_svector_ostream ccOS(SS); - getResultSourceText(Result->getCompletionString(), ccOS); + ide::printCodeCompletionResultSourceText(*Result, ccOS); } unsigned TextEnd = SS.size(); @@ -603,121 +600,6 @@ getCodeCompletionKeywordKindForUID(UIdent uid) { return CodeCompletionKeywordKind::None; } -using ChunkKind = CodeCompletionString::Chunk::ChunkKind; - -/// Provide the text for the call parameter, including constructing a typed -/// editor placeholder for it. -static void constructTextForCallParam( - ArrayRef ParamGroup, raw_ostream &OS) { - assert(ParamGroup.front().is(ChunkKind::CallParameterBegin)); - - for (; !ParamGroup.empty(); ParamGroup = ParamGroup.slice(1)) { - auto &C = ParamGroup.front(); - if (C.isAnnotation()) - continue; - if (C.is(ChunkKind::CallParameterInternalName) || - C.is(ChunkKind::CallParameterType) || - C.is(ChunkKind::CallParameterTypeBegin) || - C.is(ChunkKind::CallParameterClosureExpr)) { - break; - } - if (!C.hasText()) - continue; - OS << C.getText(); - } - - SmallString<32> DisplayString; - SmallString<32> TypeString; - SmallString<32> ExpansionTypeString; - - for (auto i = ParamGroup.begin(), e = ParamGroup.end(); i != e; ++i) { - auto &C = *i; - if (C.is(ChunkKind::CallParameterTypeBegin)) { - assert(TypeString.empty()); - auto nestingLevel = C.getNestingLevel(); - ++i; - for (; i != e; ++i) { - if (i->endsPreviousNestedGroup(nestingLevel)) - break; - if (!i->isAnnotation() && i->hasText()) { - TypeString += i->getText(); - DisplayString += i->getText(); - } - } - --i; - continue; - } - if (C.is(ChunkKind::CallParameterClosureType)) { - assert(ExpansionTypeString.empty()); - ExpansionTypeString = C.getText(); - continue; - } - if (C.is(ChunkKind::CallParameterType)) { - assert(TypeString.empty()); - TypeString = C.getText(); - } - if (C.is(ChunkKind::CallParameterClosureExpr)) { - // We have a closure expression, so provide it directly instead of in - // a placeholder. - OS << "{"; - if (!C.getText().empty()) - OS << " " << C.getText(); - OS << "\n" << getCodePlaceholder() << "\n}"; - return; - } - if (C.isAnnotation() || !C.hasText()) - continue; - DisplayString += C.getText(); - } - - StringRef Display = DisplayString.str(); - StringRef Type = TypeString.str(); - StringRef ExpansionType = ExpansionTypeString.str(); - if (ExpansionType.empty()) - ExpansionType = Type; - - OS << "<#T##" << Display; - if (Display == Type && Display == ExpansionType) { - // Short version, display and type are the same. - } else { - OS << "##" << Type; - if (ExpansionType != Type) - OS << "##" << ExpansionType; - } - OS << "#>"; -} - -void SwiftToSourceKitCompletionAdapter::getResultSourceText( - const CodeCompletionString *CCStr, raw_ostream &OS) { - auto Chunks = CCStr->getChunks(); - for (size_t i = 0; i < Chunks.size(); ++i) { - auto &C = Chunks[i]; - if (C.is(ChunkKind::BraceStmtWithCursor)) { - OS << " {\n" << getCodePlaceholder() << "\n}"; - continue; - } - if (C.is(ChunkKind::CallParameterBegin)) { - size_t Start = i++; - for (; i < Chunks.size(); ++i) { - if (Chunks[i].endsPreviousNestedGroup(C.getNestingLevel())) - break; - } - constructTextForCallParam(Chunks.slice(Start, i-Start), OS); - --i; - continue; - } - if (C.is(ChunkKind::TypeAnnotationBegin)) { - // Skip type annotation structure. - auto level = C.getNestingLevel(); - do { ++i; } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); - --i; - } - if (!C.isAnnotation() && C.hasText()) { - OS << C.getText(); - } - } -} - void SwiftToSourceKitCompletionAdapter::getResultAssociatedUSRs( ArrayRef AssocUSRs, raw_ostream &OS) { bool First = true; @@ -1140,8 +1022,7 @@ static void transformAndForwardResults( std::string str = inputBuf->getBuffer().slice(0, offset).str(); { llvm::raw_string_ostream OSS(str); - SwiftToSourceKitCompletionAdapter::getResultSourceText( - exactMatch->getCompletionString(), OSS); + ide::printCodeCompletionResultSourceText(*exactMatch, OSS); } auto buffer = From cf87ad805f3b56ccd7c13154ca1840675e4c4c89 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Aug 2020 10:34:14 -0700 Subject: [PATCH 316/663] [gardening] Move filter name printing alongside other completion methods --- .../swift/IDE/CodeCompletionResultPrinter.h | 3 + lib/IDE/CodeCompletionResultPrinter.cpp | 64 +++++++++++++++++ .../SourceKit/lib/SwiftLang/CodeCompletion.h | 6 -- .../lib/SwiftLang/CodeCompletionOrganizer.cpp | 70 +------------------ .../lib/SwiftLang/SwiftCompletion.cpp | 6 +- 5 files changed, 71 insertions(+), 78 deletions(-) diff --git a/include/swift/IDE/CodeCompletionResultPrinter.h b/include/swift/IDE/CodeCompletionResultPrinter.h index 05d4cb0f473b7..86e1233246dc9 100644 --- a/include/swift/IDE/CodeCompletionResultPrinter.h +++ b/include/swift/IDE/CodeCompletionResultPrinter.h @@ -37,6 +37,9 @@ void printCodeCompletionResultTypeNameAnnotated( void printCodeCompletionResultSourceText( const CodeCompletionResult &Result, llvm::raw_ostream &OS); +void printCodeCompletionResultFilterName( + const CodeCompletionResult &Result, llvm::raw_ostream &OS); + } // namespace ide } // namespace swift diff --git a/lib/IDE/CodeCompletionResultPrinter.cpp b/lib/IDE/CodeCompletionResultPrinter.cpp index 7da3932d33191..1e04e6a599702 100644 --- a/lib/IDE/CodeCompletionResultPrinter.cpp +++ b/lib/IDE/CodeCompletionResultPrinter.cpp @@ -368,3 +368,67 @@ void swift::ide::printCodeCompletionResultSourceText(const CodeCompletionResult } } } + +void swift::ide::printCodeCompletionResultFilterName(const CodeCompletionResult &Result, llvm::raw_ostream &OS) { + auto str = Result.getCompletionString(); + // FIXME: we need a more uniform way to handle operator completions. + if (str->getChunks().size() == 1 && str->getChunks()[0].is(ChunkKind::Dot)) { + OS << "."; + return; + } else if (str->getChunks().size() == 2 && + str->getChunks()[0].is(ChunkKind::QuestionMark) && + str->getChunks()[1].is(ChunkKind::Dot)) { + OS << "?."; + return; + } + + auto FirstTextChunk = str->getFirstTextChunkIndex(); + if (FirstTextChunk.hasValue()) { + auto chunks = str->getChunks().slice(*FirstTextChunk); + for (auto i = chunks.begin(), e = chunks.end(); i != e; ++i) { + auto &C = *i; + + if (C.is(ChunkKind::BraceStmtWithCursor)) + break; // Don't include brace-stmt in filter name. + + if (C.is(ChunkKind::Equal)) { + OS << C.getText(); + break; + } + + bool shouldPrint = !C.isAnnotation(); + switch (C.getKind()) { + case ChunkKind::TypeAnnotation: + case ChunkKind::CallParameterInternalName: + case ChunkKind::CallParameterClosureType: + case ChunkKind::CallParameterClosureExpr: + case ChunkKind::CallParameterType: + case ChunkKind::DeclAttrParamColon: + case ChunkKind::Comma: + case ChunkKind::Whitespace: + case ChunkKind::Ellipsis: + case ChunkKind::Ampersand: + case ChunkKind::OptionalMethodCallTail: + continue; + case ChunkKind::CallParameterTypeBegin: + case ChunkKind::TypeAnnotationBegin: { + // Skip call parameter type or type annotation structure. + auto nestingLevel = C.getNestingLevel(); + do { ++i; } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); + --i; + continue; + } + case ChunkKind::CallParameterColon: + // Since we don't add the type, also don't add the space after ':'. + if (shouldPrint) + OS << ":"; + continue; + default: + break; + } + + if (C.hasText() && shouldPrint) + OS << C.getText(); + } + } +} diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h index 266282ab3f15b..f8098fbaf8390 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h @@ -132,12 +132,6 @@ class CompletionBuilder { Optional moduleImportDepth; PopularityFactor popularityFactor; -public: - static void getFilterName(CodeCompletionString *str, raw_ostream &OS); - static void getDescription(SwiftResult *result, raw_ostream &OS, - bool leadingPunctuation, - bool annotatedDecription = false); - public: CompletionBuilder(CompletionSink &sink, SwiftResult &base); diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index a7864e91cc65a..c24e17a0e1afd 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -1209,72 +1209,6 @@ bool LimitedResultView::walk(CodeCompletionView::Walker &walker) const { // CompletionBuilder //===----------------------------------------------------------------------===// -void CompletionBuilder::getFilterName(CodeCompletionString *str, - raw_ostream &OS) { - using ChunkKind = CodeCompletionString::Chunk::ChunkKind; - - // FIXME: we need a more uniform way to handle operator completions. - if (str->getChunks().size() == 1 && str->getChunks()[0].is(ChunkKind::Dot)) { - OS << "."; - return; - } else if (str->getChunks().size() == 2 && - str->getChunks()[0].is(ChunkKind::QuestionMark) && - str->getChunks()[1].is(ChunkKind::Dot)) { - OS << "?."; - return; - } - - auto FirstTextChunk = str->getFirstTextChunkIndex(); - if (FirstTextChunk.hasValue()) { - auto chunks = str->getChunks().slice(*FirstTextChunk); - for (auto i = chunks.begin(), e = chunks.end(); i != e; ++i) { - auto &C = *i; - - if (C.is(ChunkKind::BraceStmtWithCursor)) - break; // Don't include brace-stmt in filter name. - - if (C.is(ChunkKind::Equal)) { - OS << C.getText(); - break; - } - - bool shouldPrint = !C.isAnnotation(); - switch (C.getKind()) { - case ChunkKind::TypeAnnotation: - case ChunkKind::CallParameterInternalName: - case ChunkKind::CallParameterClosureType: - case ChunkKind::CallParameterClosureExpr: - case ChunkKind::CallParameterType: - case ChunkKind::DeclAttrParamColon: - case ChunkKind::Comma: - case ChunkKind::Whitespace: - case ChunkKind::Ellipsis: - case ChunkKind::Ampersand: - case ChunkKind::OptionalMethodCallTail: - continue; - case ChunkKind::CallParameterTypeBegin: - case ChunkKind::TypeAnnotationBegin: { - // Skip call parameter type or type annotation structure. - auto nestingLevel = C.getNestingLevel(); - do { ++i; } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); - --i; - continue; - } - case ChunkKind::CallParameterColon: - // Since we don't add the type, also don't add the space after ':'. - if (shouldPrint) - OS << ":"; - continue; - default: - break; - } - - if (C.hasText() && shouldPrint) - OS << C.getText(); - } - } -} - CompletionBuilder::CompletionBuilder(CompletionSink &sink, SwiftResult &base) : sink(sink), current(base) { typeRelation = current.getExpectedTypeRelation(); @@ -1286,7 +1220,7 @@ CompletionBuilder::CompletionBuilder(CompletionSink &sink, SwiftResult &base) // strings for our inner "." result. if (current.getCompletionString()->getFirstTextChunkIndex().hasValue()) { llvm::raw_svector_ostream OSS(originalName); - getFilterName(current.getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(current, OSS); } } @@ -1336,7 +1270,7 @@ Completion *CompletionBuilder::finish() { } llvm::raw_svector_ostream OSS(nameStorage); - getFilterName(base.getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(base, OSS); name = OSS.str(); } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index c0ab78cb37825..06d3a912d4b51 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -49,8 +49,7 @@ struct SwiftToSourceKitCompletionAdapter { llvm::SmallString<64> name; { llvm::raw_svector_ostream OSS(name); - CodeCompletion::CompletionBuilder::getFilterName( - result->getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(*result, OSS); } llvm::SmallString<64> description; @@ -887,8 +886,7 @@ filterInnerResults(ArrayRef results, bool includeInner, llvm::SmallString<64> filterName; { llvm::raw_svector_ostream OSS(filterName); - CodeCompletion::CompletionBuilder::getFilterName( - result->getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(*result, OSS); } llvm::SmallString<64> description; { From af78895c453398575151ace94ee5732451060b2f Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Aug 2020 10:20:18 -0700 Subject: [PATCH 317/663] [gardening] Sink compiler invocation code into libIDE --- include/swift/IDE/Utils.h | 8 + lib/IDE/Utils.cpp | 185 ++++++++++++++++++ .../lib/SwiftLang/SwiftASTManager.cpp | 166 +--------------- 3 files changed, 194 insertions(+), 165 deletions(-) diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index f847b188f1b42..8eaf34a69b5e7 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -81,6 +81,14 @@ SourceCompleteResult isSourceInputComplete(std::unique_ptr MemBuf, SourceFileKind SFKind); SourceCompleteResult isSourceInputComplete(StringRef Text, SourceFileKind SFKind); +bool initCompilerInvocation( + CompilerInvocation &Invocation, ArrayRef OrigArgs, + DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + const std::string &runtimeResourcePath, + const std::string &diagnosticDocumentationPath, + bool shouldOptimizeForIDE, time_t sessionTimestamp, std::string &Error); + bool initInvocationByClangArguments(ArrayRef ArgList, CompilerInvocation &Invok, std::string &Error); diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 616a0e6e0678f..2133ac9ecf41f 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -14,6 +14,7 @@ #include "swift/Basic/Edit.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangModule.h" +#include "swift/Driver/FrontendUtil.h" #include "swift/Frontend/Frontend.h" #include "swift/Parse/Parser.h" #include "swift/Subsystems.h" @@ -226,6 +227,190 @@ static std::string adjustClangTriple(StringRef TripleStr) { return Result; } +static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( + FrontendInputsAndOutputs &inputsAndOutputs, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + std::string &Error) { + assert(FileSystem); + + llvm::SmallString<128> PrimaryFile; + if (auto err = FileSystem->getRealPath(UnresolvedPrimaryFile, PrimaryFile)) + PrimaryFile = UnresolvedPrimaryFile; + + unsigned primaryCount = 0; + // FIXME: The frontend should be dealing with symlinks, maybe similar to + // clang's FileManager ? + FrontendInputsAndOutputs replacementInputsAndOutputs; + for (const InputFile &input : inputsAndOutputs.getAllInputs()) { + llvm::SmallString<128> newFilename; + if (auto err = FileSystem->getRealPath(input.file(), newFilename)) + newFilename = input.file(); + llvm::sys::path::native(newFilename); + bool newIsPrimary = input.isPrimary() || + (!PrimaryFile.empty() && PrimaryFile == newFilename); + if (newIsPrimary) { + ++primaryCount; + } + assert(primaryCount < 2 && "cannot handle multiple primaries"); + replacementInputsAndOutputs.addInput( + InputFile(newFilename.str(), newIsPrimary, input.buffer())); + } + + if (PrimaryFile.empty() || primaryCount == 1) { + return replacementInputsAndOutputs; + } + + llvm::SmallString<64> Err; + llvm::raw_svector_ostream OS(Err); + OS << "'" << PrimaryFile << "' is not part of the input files"; + Error = std::string(OS.str()); + return replacementInputsAndOutputs; +} + +static void disableExpensiveSILOptions(SILOptions &Opts) { + // Disable the sanitizers. + Opts.Sanitizers = {}; + + // Disable PGO and code coverage. + Opts.GenerateProfile = false; + Opts.EmitProfileCoverageMapping = false; + Opts.UseProfile = ""; +} + +namespace { +class StreamDiagConsumer : public DiagnosticConsumer { + llvm::raw_ostream &OS; + +public: + StreamDiagConsumer(llvm::raw_ostream &OS) : OS(OS) {} + + void handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) override { + // FIXME: Print location info if available. + switch (Info.Kind) { + case DiagnosticKind::Error: + OS << "error: "; + break; + case DiagnosticKind::Warning: + OS << "warning: "; + break; + case DiagnosticKind::Note: + OS << "note: "; + break; + case DiagnosticKind::Remark: + OS << "remark: "; + break; + } + DiagnosticEngine::formatDiagnosticText(OS, Info.FormatString, + Info.FormatArgs); + } +}; +} // end anonymous namespace + +bool ide::initCompilerInvocation( + CompilerInvocation &Invocation, ArrayRef OrigArgs, + DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + const std::string &runtimeResourcePath, + const std::string &diagnosticDocumentationPath, + bool shouldOptimizeForIDE, time_t sessionTimestamp, std::string &Error) { + SmallVector Args; + // Make sure to put '-resource-dir' and '-diagnostic-documentation-path' at + // the top to allow overriding them with the passed in arguments. + Args.push_back("-resource-dir"); + Args.push_back(runtimeResourcePath.c_str()); + Args.push_back("-Xfrontend"); + Args.push_back("-diagnostic-documentation-path"); + Args.push_back("-Xfrontend"); + Args.push_back(diagnosticDocumentationPath.c_str()); + Args.append(OrigArgs.begin(), OrigArgs.end()); + + SmallString<32> ErrStr; + llvm::raw_svector_ostream ErrOS(ErrStr); + StreamDiagConsumer DiagConsumer(ErrOS); + Diags.addConsumer(DiagConsumer); + + bool HadError = driver::getSingleFrontendInvocationFromDriverArguments( + Args, Diags, [&](ArrayRef FrontendArgs) { + return Invocation.parseArgs(FrontendArgs, Diags); + }, /*ForceNoOutputs=*/true); + + // Remove the StreamDiagConsumer as it's no longer needed. + Diags.removeConsumer(DiagConsumer); + + if (HadError) { + Error = std::string(ErrOS.str()); + return true; + } + + Invocation.getFrontendOptions().InputsAndOutputs = + resolveSymbolicLinksInInputs( + Invocation.getFrontendOptions().InputsAndOutputs, + UnresolvedPrimaryFile, FileSystem, Error); + if (!Error.empty()) + return true; + + ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions(); + ImporterOpts.DetailedPreprocessingRecord = true; + + assert(!Invocation.getModuleName().empty()); + + auto &LangOpts = Invocation.getLangOptions(); + LangOpts.AttachCommentsToDecls = true; + LangOpts.DiagnosticsEditorMode = true; + LangOpts.CollectParsedToken = true; + if (LangOpts.PlaygroundTransform) { + // The playground instrumenter changes the AST in ways that disrupt the + // SourceKit functionality. Since we don't need the instrumenter, and all we + // actually need is the playground semantics visible to the user, like + // silencing the "expression resolves to an unused l-value" error, disable it. + LangOpts.PlaygroundTransform = false; + } + + // Disable the index-store functionality for the sourcekitd requests. + auto &FrontendOpts = Invocation.getFrontendOptions(); + FrontendOpts.IndexStorePath.clear(); + ImporterOpts.IndexStorePath.clear(); + + // Force the action type to be -typecheck. This affects importing the + // SwiftONoneSupport module. + FrontendOpts.RequestedAction = FrontendOptions::ActionType::Typecheck; + + // We don't care about LLVMArgs + FrontendOpts.LLVMArgs.clear(); + + // SwiftSourceInfo files provide source location information for decls coming + // from loaded modules. For most IDE use cases it either has an undesirable + // impact on performance with no benefit (code completion), results in stale + // locations being used instead of more up-to-date indexer locations (cursor + // info), or has no observable effect (diagnostics, which are filtered to just + // those with a location in the primary file, and everything else). + if (shouldOptimizeForIDE) + FrontendOpts.IgnoreSwiftSourceInfo = true; + + // To save the time for module validation, consider the lifetime of ASTManager + // as a single build session. + // NOTE: Do this only if '-disable-modules-validate-system-headers' is *not* + // explicitly enabled. + auto &SearchPathOpts = Invocation.getSearchPathOptions(); + if (!SearchPathOpts.DisableModulesValidateSystemDependencies) { + // NOTE: 'SessionTimestamp - 1' because clang compares it with '<=' that may + // cause unnecessary validations if they happens within one second + // from the SourceKit startup. + ImporterOpts.ExtraArgs.push_back("-fbuild-session-timestamp=" + + std::to_string(sessionTimestamp - 1)); + ImporterOpts.ExtraArgs.push_back( + "-fmodules-validate-once-per-build-session"); + + SearchPathOpts.DisableModulesValidateSystemDependencies = true; + } + + // Disable expensive SIL options to reduce time spent in SILGen. + disableExpensiveSILOptions(Invocation.getSILOptions()); + + return false; +} + bool ide::initInvocationByClangArguments(ArrayRef ArgList, CompilerInvocation &Invok, std::string &Error) { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 7b30a003845b7..9bc69165c0183 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -40,36 +40,6 @@ using namespace SourceKit; using namespace swift; using namespace swift::sys; -namespace { -class StreamDiagConsumer : public DiagnosticConsumer { - llvm::raw_ostream &OS; - -public: - StreamDiagConsumer(llvm::raw_ostream &OS) : OS(OS) {} - - void handleDiagnostic(SourceManager &SM, - const DiagnosticInfo &Info) override { - // FIXME: Print location info if available. - switch (Info.Kind) { - case DiagnosticKind::Error: - OS << "error: "; - break; - case DiagnosticKind::Warning: - OS << "warning: "; - break; - case DiagnosticKind::Note: - OS << "note: "; - break; - case DiagnosticKind::Remark: - OS << "remark: "; - break; - } - DiagnosticEngine::formatDiagnosticText(OS, Info.FormatString, - Info.FormatArgs); - } -}; -} // end anonymous namespace - void SwiftASTConsumer::failed(StringRef Error) { } //===----------------------------------------------------------------------===// @@ -433,46 +403,6 @@ convertFileContentsToInputs(const SmallVectorImpl &contents) { return inputsAndOutputs; } -static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( - FrontendInputsAndOutputs &inputsAndOutputs, StringRef UnresolvedPrimaryFile, - llvm::IntrusiveRefCntPtr FileSystem, - std::string &Error) { - assert(FileSystem); - - llvm::SmallString<128> PrimaryFile; - if (auto err = FileSystem->getRealPath(UnresolvedPrimaryFile, PrimaryFile)) - PrimaryFile = UnresolvedPrimaryFile; - - unsigned primaryCount = 0; - // FIXME: The frontend should be dealing with symlinks, maybe similar to - // clang's FileManager ? - FrontendInputsAndOutputs replacementInputsAndOutputs; - for (const InputFile &input : inputsAndOutputs.getAllInputs()) { - llvm::SmallString<128> newFilename; - if (auto err = FileSystem->getRealPath(input.file(), newFilename)) - newFilename = input.file(); - llvm::sys::path::native(newFilename); - bool newIsPrimary = input.isPrimary() || - (!PrimaryFile.empty() && PrimaryFile == newFilename); - if (newIsPrimary) { - ++primaryCount; - } - assert(primaryCount < 2 && "cannot handle multiple primaries"); - replacementInputsAndOutputs.addInput( - InputFile(newFilename.str(), newIsPrimary, input.buffer())); - } - - if (PrimaryFile.empty() || primaryCount == 1) { - return replacementInputsAndOutputs; - } - - llvm::SmallString<64> Err; - llvm::raw_svector_ostream OS(Err); - OS << "'" << PrimaryFile << "' is not part of the input files"; - Error = std::string(OS.str()); - return replacementInputsAndOutputs; -} - bool SwiftASTManager::initCompilerInvocation( CompilerInvocation &Invocation, ArrayRef OrigArgs, DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, @@ -488,101 +418,7 @@ bool SwiftASTManager::initCompilerInvocation( DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, llvm::IntrusiveRefCntPtr FileSystem, std::string &Error) { - SmallVector Args; - // Make sure to put '-resource-dir' and '-diagnostic-documentation-path' at - // the top to allow overriding them with the passed in arguments. - Args.push_back("-resource-dir"); - Args.push_back(Impl.RuntimeResourcePath.c_str()); - Args.push_back("-Xfrontend"); - Args.push_back("-diagnostic-documentation-path"); - Args.push_back("-Xfrontend"); - Args.push_back(Impl.DiagnosticDocumentationPath.c_str()); - Args.append(OrigArgs.begin(), OrigArgs.end()); - - SmallString<32> ErrStr; - llvm::raw_svector_ostream ErrOS(ErrStr); - StreamDiagConsumer DiagConsumer(ErrOS); - Diags.addConsumer(DiagConsumer); - - bool HadError = driver::getSingleFrontendInvocationFromDriverArguments( - Args, Diags, [&](ArrayRef FrontendArgs) { - return Invocation.parseArgs(FrontendArgs, Diags); - }, /*ForceNoOutputs=*/true); - - // Remove the StreamDiagConsumer as it's no longer needed. - Diags.removeConsumer(DiagConsumer); - - if (HadError) { - Error = std::string(ErrOS.str()); - return true; - } - - Invocation.getFrontendOptions().InputsAndOutputs = - resolveSymbolicLinksInInputs( - Invocation.getFrontendOptions().InputsAndOutputs, - UnresolvedPrimaryFile, FileSystem, Error); - if (!Error.empty()) - return true; - - ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions(); - ImporterOpts.DetailedPreprocessingRecord = true; - - assert(!Invocation.getModuleName().empty()); - - auto &LangOpts = Invocation.getLangOptions(); - LangOpts.AttachCommentsToDecls = true; - LangOpts.DiagnosticsEditorMode = true; - LangOpts.CollectParsedToken = true; - if (LangOpts.PlaygroundTransform) { - // The playground instrumenter changes the AST in ways that disrupt the - // SourceKit functionality. Since we don't need the instrumenter, and all we - // actually need is the playground semantics visible to the user, like - // silencing the "expression resolves to an unused l-value" error, disable it. - LangOpts.PlaygroundTransform = false; - } - - // Disable the index-store functionality for the sourcekitd requests. - auto &FrontendOpts = Invocation.getFrontendOptions(); - FrontendOpts.IndexStorePath.clear(); - ImporterOpts.IndexStorePath.clear(); - - // Force the action type to be -typecheck. This affects importing the - // SwiftONoneSupport module. - FrontendOpts.RequestedAction = FrontendOptions::ActionType::Typecheck; - - // We don't care about LLVMArgs - FrontendOpts.LLVMArgs.clear(); - - // SwiftSourceInfo files provide source location information for decls coming - // from loaded modules. For most IDE use cases it either has an undesirable - // impact on performance with no benefit (code completion), results in stale - // locations being used instead of more up-to-date indexer locations (cursor - // info), or has no observable effect (diagnostics, which are filtered to just - // those with a location in the primary file, and everything else). - if (Impl.Config->shouldOptimizeForIDE()) - FrontendOpts.IgnoreSwiftSourceInfo = true; - - // To save the time for module validation, consider the lifetime of ASTManager - // as a single build session. - // NOTE: Do this only if '-disable-modules-validate-system-headers' is *not* - // explicitly enabled. - auto &SearchPathOpts = Invocation.getSearchPathOptions(); - if (!SearchPathOpts.DisableModulesValidateSystemDependencies) { - // NOTE: 'SessionTimestamp - 1' because clang compares it with '<=' that may - // cause unnecessary validations if they happens within one second - // from the SourceKit startup. - ImporterOpts.ExtraArgs.push_back("-fbuild-session-timestamp=" + - std::to_string(Impl.SessionTimestamp - 1)); - ImporterOpts.ExtraArgs.push_back( - "-fmodules-validate-once-per-build-session"); - - SearchPathOpts.DisableModulesValidateSystemDependencies = true; - } - - // Disable expensive SIL options to reduce time spent in SILGen. - disableExpensiveSILOptions(Invocation.getSILOptions()); - - return false; + return ide::initCompilerInvocation(Invocation, OrigArgs, Diags, UnresolvedPrimaryFile, FileSystem, Impl.RuntimeResourcePath, Impl.DiagnosticDocumentationPath, Impl.Config->shouldOptimizeForIDE(), Impl.SessionTimestamp, Error); } bool SwiftASTManager::initCompilerInvocation(CompilerInvocation &CompInvok, From 0d42d7d915357f73d0c5ff4040d6be3200817a0a Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Aug 2020 10:43:29 -0700 Subject: [PATCH 318/663] [gardening] format changed code --- lib/IDE/CodeCompletionResultPrinter.cpp | 27 ++++++++++++------- .../lib/SwiftLang/SwiftASTManager.cpp | 5 +++- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/IDE/CodeCompletionResultPrinter.cpp b/lib/IDE/CodeCompletionResultPrinter.cpp index 1e04e6a599702..7b61aa1835153 100644 --- a/lib/IDE/CodeCompletionResultPrinter.cpp +++ b/lib/IDE/CodeCompletionResultPrinter.cpp @@ -10,9 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/LLVM.h" -#include "swift/AST/ASTPrinter.h" #include "swift/IDE/CodeCompletionResultPrinter.h" +#include "swift/AST/ASTPrinter.h" +#include "swift/Basic/LLVM.h" #include "swift/IDE/CodeCompletion.h" #include "swift/Markup/XMLUtils.h" #include "llvm/Support/raw_ostream.h" @@ -259,8 +259,9 @@ void swift::ide::printCodeCompletionResultTypeNameAnnotated(const CodeCompletion /// Provide the text for the call parameter, including constructing a typed /// editor placeholder for it. -static void constructTextForCallParam( - ArrayRef ParamGroup, raw_ostream &OS) { +static void +constructTextForCallParam(ArrayRef ParamGroup, + raw_ostream &OS) { assert(ParamGroup.front().is(ChunkKind::CallParameterBegin)); for (; !ParamGroup.empty(); ParamGroup = ParamGroup.slice(1)) { @@ -339,7 +340,8 @@ static void constructTextForCallParam( OS << "#>"; } -void swift::ide::printCodeCompletionResultSourceText(const CodeCompletionResult &Result, llvm::raw_ostream &OS) { +void swift::ide::printCodeCompletionResultSourceText( + const CodeCompletionResult &Result, llvm::raw_ostream &OS) { auto Chunks = Result.getCompletionString()->getChunks(); for (size_t i = 0; i < Chunks.size(); ++i) { auto &C = Chunks[i]; @@ -353,14 +355,16 @@ void swift::ide::printCodeCompletionResultSourceText(const CodeCompletionResult if (Chunks[i].endsPreviousNestedGroup(C.getNestingLevel())) break; } - constructTextForCallParam(Chunks.slice(Start, i-Start), OS); + constructTextForCallParam(Chunks.slice(Start, i - Start), OS); --i; continue; } if (C.is(ChunkKind::TypeAnnotationBegin)) { // Skip type annotation structure. auto level = C.getNestingLevel(); - do { ++i; } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); + do { + ++i; + } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); --i; } if (!C.isAnnotation() && C.hasText()) { @@ -369,7 +373,8 @@ void swift::ide::printCodeCompletionResultSourceText(const CodeCompletionResult } } -void swift::ide::printCodeCompletionResultFilterName(const CodeCompletionResult &Result, llvm::raw_ostream &OS) { +void swift::ide::printCodeCompletionResultFilterName( + const CodeCompletionResult &Result, llvm::raw_ostream &OS) { auto str = Result.getCompletionString(); // FIXME: we need a more uniform way to handle operator completions. if (str->getChunks().size() == 1 && str->getChunks()[0].is(ChunkKind::Dot)) { @@ -414,7 +419,9 @@ void swift::ide::printCodeCompletionResultFilterName(const CodeCompletionResult case ChunkKind::TypeAnnotationBegin: { // Skip call parameter type or type annotation structure. auto nestingLevel = C.getNestingLevel(); - do { ++i; } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); + do { + ++i; + } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); --i; continue; } @@ -430,5 +437,5 @@ void swift::ide::printCodeCompletionResultFilterName(const CodeCompletionResult if (C.hasText() && shouldPrint) OS << C.getText(); } - } + } } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 9bc69165c0183..dfc5ea55b7daf 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -418,7 +418,10 @@ bool SwiftASTManager::initCompilerInvocation( DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, llvm::IntrusiveRefCntPtr FileSystem, std::string &Error) { - return ide::initCompilerInvocation(Invocation, OrigArgs, Diags, UnresolvedPrimaryFile, FileSystem, Impl.RuntimeResourcePath, Impl.DiagnosticDocumentationPath, Impl.Config->shouldOptimizeForIDE(), Impl.SessionTimestamp, Error); + return ide::initCompilerInvocation( + Invocation, OrigArgs, Diags, UnresolvedPrimaryFile, FileSystem, + Impl.RuntimeResourcePath, Impl.DiagnosticDocumentationPath, + Impl.Config->shouldOptimizeForIDE(), Impl.SessionTimestamp, Error); } bool SwiftASTManager::initCompilerInvocation(CompilerInvocation &CompInvok, From 81786104f356b523fb5582c5725041f8fc7e4ce2 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Aug 2020 11:16:53 -0700 Subject: [PATCH 319/663] Move adjustClangTriple above its only caller --- lib/IDE/Utils.cpp | 76 +++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 2133ac9ecf41f..5d0dda4b8e555 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -189,44 +189,6 @@ ide::isSourceInputComplete(StringRef Text,SourceFileKind SFKind) { SFKind); } -// Adjust the cc1 triple string we got from clang, to make sure it will be -// accepted when it goes through the swift clang importer. -static std::string adjustClangTriple(StringRef TripleStr) { - std::string Result; - llvm::raw_string_ostream OS(Result); - - llvm::Triple Triple(TripleStr); - switch (Triple.getSubArch()) { - case llvm::Triple::SubArchType::ARMSubArch_v7: - OS << "armv7"; break; - case llvm::Triple::SubArchType::ARMSubArch_v7s: - OS << "armv7s"; break; - case llvm::Triple::SubArchType::ARMSubArch_v7k: - OS << "armv7k"; break; - case llvm::Triple::SubArchType::ARMSubArch_v6: - OS << "armv6"; break; - case llvm::Triple::SubArchType::ARMSubArch_v6m: - OS << "armv6m"; break; - case llvm::Triple::SubArchType::ARMSubArch_v6k: - OS << "armv6k"; break; - case llvm::Triple::SubArchType::ARMSubArch_v6t2: - OS << "armv6t2"; break; - default: - // Adjust i386-macosx to x86_64 because there is no Swift stdlib for i386. - if ((Triple.getOS() == llvm::Triple::MacOSX || - Triple.getOS() == llvm::Triple::Darwin) && Triple.getArch() == llvm::Triple::x86) { - OS << "x86_64"; - } else { - OS << Triple.getArchName(); - } - break; - } - OS << '-' << Triple.getVendorName() << '-' << - Triple.getOSAndEnvironmentName(); - OS.flush(); - return Result; -} - static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( FrontendInputsAndOutputs &inputsAndOutputs, StringRef UnresolvedPrimaryFile, llvm::IntrusiveRefCntPtr FileSystem, @@ -411,6 +373,44 @@ bool ide::initCompilerInvocation( return false; } +// Adjust the cc1 triple string we got from clang, to make sure it will be +// accepted when it goes through the swift clang importer. +static std::string adjustClangTriple(StringRef TripleStr) { + std::string Result; + llvm::raw_string_ostream OS(Result); + + llvm::Triple Triple(TripleStr); + switch (Triple.getSubArch()) { + case llvm::Triple::SubArchType::ARMSubArch_v7: + OS << "armv7"; break; + case llvm::Triple::SubArchType::ARMSubArch_v7s: + OS << "armv7s"; break; + case llvm::Triple::SubArchType::ARMSubArch_v7k: + OS << "armv7k"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6: + OS << "armv6"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6m: + OS << "armv6m"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6k: + OS << "armv6k"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6t2: + OS << "armv6t2"; break; + default: + // Adjust i386-macosx to x86_64 because there is no Swift stdlib for i386. + if ((Triple.getOS() == llvm::Triple::MacOSX || + Triple.getOS() == llvm::Triple::Darwin) && Triple.getArch() == llvm::Triple::x86) { + OS << "x86_64"; + } else { + OS << Triple.getArchName(); + } + break; + } + OS << '-' << Triple.getVendorName() << '-' << + Triple.getOSAndEnvironmentName(); + OS.flush(); + return Result; +} + bool ide::initInvocationByClangArguments(ArrayRef ArgList, CompilerInvocation &Invok, std::string &Error) { From 696c124af7b1031dfcadeef89797e0f8bad95dd6 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Aug 2020 11:45:11 -0700 Subject: [PATCH 320/663] Fix missing dependency --- lib/IDE/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt index e7529a25a89d5..d028e874d39b7 100644 --- a/lib/IDE/CMakeLists.txt +++ b/lib/IDE/CMakeLists.txt @@ -22,6 +22,7 @@ add_swift_host_library(swiftIDE STATIC target_link_libraries(swiftIDE PRIVATE swiftAST swiftClangImporter + swiftDriver swiftFrontend swiftIndex swiftParse From 6e6de518eb46ef208dfa5deae54891583f3f9951 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Tue, 25 Aug 2020 20:02:52 +0100 Subject: [PATCH 321/663] [Sema] Improve diagnostics for use of self access kind modifier on accessors inside classes (#33602) --- include/swift/AST/DiagnosticsSema.def | 5 +++-- lib/Sema/TypeCheckAttr.cpp | 9 ++++++--- localization/diagnostics/en.yaml | 2 +- test/Sema/immutability.swift | 17 +++++++++++++---- test/decl/ext/extensions.swift | 12 ++++++------ 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 8424bd9810a8f..beaf7b6ea3dd5 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1294,8 +1294,9 @@ ERROR(nominal_type_not_attribute,none, ERROR(mutating_invalid_global_scope,none, "%0 is only valid on methods", (SelfAccessKind)) -ERROR(mutating_invalid_classes,none, "%0 isn't valid on methods in " - "classes or class-bound protocols", (SelfAccessKind)) +ERROR(mutating_invalid_classes,none, "%0 is not valid on %1s in " + "%select{classes|class-bound protocols}2", + (SelfAccessKind, DescriptiveDeclKind, bool)) ERROR(functions_mutating_and_not,none, "method must not be declared both %0 and %1", diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 4d15582ff9f91..94478abf4f50f 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -317,14 +317,17 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) { llvm_unreachable("unhandled attribute kind"); } + auto DC = FD->getDeclContext(); // mutation attributes may only appear in type context. - if (auto contextTy = FD->getDeclContext()->getDeclaredInterfaceType()) { + if (auto contextTy = DC->getDeclaredInterfaceType()) { // 'mutating' and 'nonmutating' are not valid on types // with reference semantics. if (contextTy->hasReferenceSemantics()) { - if (attrModifier != SelfAccessKind::Consuming) + if (attrModifier != SelfAccessKind::Consuming) { diagnoseAndRemoveAttr(attr, diag::mutating_invalid_classes, - attrModifier); + attrModifier, FD->getDescriptiveKind(), + DC->getSelfProtocolDecl() != nullptr); + } } } else { diagnoseAndRemoveAttr(attr, diag::mutating_invalid_global_scope, diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index d469f67329008..b346b96b115cc 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -3350,7 +3350,7 @@ msg: "%0 is only valid on methods" - id: mutating_invalid_classes - msg: "%0 isn't valid on methods in classes or class-bound protocols" + msg: "%0 is not valid on %1s in %select{classes|class-bound protocols}2" - id: functions_mutating_and_not msg: "method must not be declared both %0 and %1" diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift index beae8a87fa53e..d43c5c299b806 100644 --- a/test/Sema/immutability.swift +++ b/test/Sema/immutability.swift @@ -61,13 +61,13 @@ class FooClass { mutating init(a : Bool) {} // expected-error {{'mutating' may only be used on 'func' declarations}} {{3-12=}} - mutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} {{3-12=}} + mutating // expected-error {{'mutating' is not valid on instance methods in classes}} {{3-12=}} func baz() {} - nonmutating // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} {{3-15=}} + nonmutating // expected-error {{'nonmutating' is not valid on instance methods in classes}} {{3-15=}} func bay() {} - mutating nonmutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + mutating nonmutating // expected-error {{'mutating' is not valid on instance methods in classes}} expected-error {{'nonmutating' is not valid on instance methods in classes}} func bax() {} var x : Int { @@ -86,6 +86,15 @@ class FooClass { } } + var computed: Int { + mutating get { 0 } // expected-error {{'mutating' is not valid on getters in classes}} {{5-14=}} + nonmutating set {} // expected-error {{'nonmutating' is not valid on setters in classes}} {{5-17=}} + } + + var storedWithObservers: Int = 0 { + mutating willSet {} // expected-error {{'mutating' is not valid on willSet observers in classes}} {{5-14=}} + nonmutating didSet {} // expected-error {{'nonmutating' is not valid on didSet observers in classes}} {{5-17=}} + } } @@ -241,7 +250,7 @@ func test_arguments(_ a : Int, protocol ClassBoundProtocolMutating : class { - mutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} {{3-12=}} + mutating // expected-error {{'mutating' is not valid on instance methods in class-bound protocols}} {{3-12=}} func f() } diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index 6729bba8d1e07..b6f5133acfd8d 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -267,14 +267,14 @@ extension ImposeClassReq1 where Self: AnyObject { var wrappingProperty2: Int { get { return someProperty } - mutating set { someProperty = newValue } // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} + mutating set { someProperty = newValue } // expected-error {{'mutating' is not valid on setters in class-bound protocols}} } - mutating func foo() { // expected-error {{mutating' isn't valid on methods in classes or class-bound protocols}} + mutating func foo() { // expected-error {{mutating' is not valid on instance methods in class-bound protocols}} someProperty = 1 } - nonmutating func bar() { // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + nonmutating func bar() { // expected-error {{'nonmutating' is not valid on instance methods in class-bound protocols}} someProperty = 2 } @@ -309,14 +309,14 @@ extension ImposeClassReq2 { var wrappingProperty2: Int { get { return someProperty } - mutating set { someProperty = newValue } // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} + mutating set { someProperty = newValue } // expected-error {{'mutating' is not valid on setters in class-bound protocols}} } - mutating func foo() { // expected-error {{mutating' isn't valid on methods in classes or class-bound protocols}} + mutating func foo() { // expected-error {{mutating' is not valid on instance methods in class-bound protocols}} someProperty = 1 } - nonmutating func bar() { // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + nonmutating func bar() { // expected-error {{'nonmutating' is not valid on instance methods in class-bound protocols}} someProperty = 2 } From ee8ad7bb8b2855122004947ca423bb517d952c31 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Tue, 25 Aug 2020 12:54:55 -0700 Subject: [PATCH 322/663] [AutoDiff] NFC: silence no-asserts unused variable warning. (#33629) --- lib/SILOptimizer/Differentiation/PullbackCloner.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 9de979b76d0f8..7b0c3c62fda76 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -2035,12 +2035,10 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( SILBasicBlock *bb, SILValue optionalValue, SILValue wrappedAdjoint) { auto pbLoc = getPullback().getLocation(); // Handle `switch_enum` on `Optional`. - auto *optionalEnumDecl = getASTContext().getOptionalDecl(); - auto optionalTy = optionalValue->getType(); - assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == - optionalEnumDecl); // `Optional` - optionalTy = remapType(optionalTy); + auto optionalTy = remapType(optionalValue->getType()); + assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == + getASTContext().getOptionalDecl()); // `T` auto wrappedType = optionalTy.getOptionalObjectType(); // `T.TangentVector` From c5b42aca1133eefa909bef1bce25ba7834f66bff Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Aug 2020 13:00:35 -0700 Subject: [PATCH 323/663] Move FuzzyStringMatcherTest to IDE unittests --- unittests/IDE/CMakeLists.txt | 1 + unittests/{SourceKit/Support => IDE}/FuzzyStringMatcherTest.cpp | 0 unittests/SourceKit/Support/CMakeLists.txt | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename unittests/{SourceKit/Support => IDE}/FuzzyStringMatcherTest.cpp (100%) diff --git a/unittests/IDE/CMakeLists.txt b/unittests/IDE/CMakeLists.txt index f55846dd2c6ad..607a574214a71 100644 --- a/unittests/IDE/CMakeLists.txt +++ b/unittests/IDE/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_unittest(SwiftIDETests CodeCompletionToken.cpp + FuzzyStringMatcherTest.cpp Placeholders.cpp ) target_link_libraries(SwiftIDETests diff --git a/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp b/unittests/IDE/FuzzyStringMatcherTest.cpp similarity index 100% rename from unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp rename to unittests/IDE/FuzzyStringMatcherTest.cpp diff --git a/unittests/SourceKit/Support/CMakeLists.txt b/unittests/SourceKit/Support/CMakeLists.txt index da17a059b87b3..54cbdce081c87 100644 --- a/unittests/SourceKit/Support/CMakeLists.txt +++ b/unittests/SourceKit/Support/CMakeLists.txt @@ -1,5 +1,4 @@ add_swift_unittest(SourceKitSupportTests - FuzzyStringMatcherTest.cpp ImmutableTextBufferTest.cpp ) From 94b5f7665478c09d34af663c611b4662ee478af4 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 25 Aug 2020 12:54:45 -0700 Subject: [PATCH 324/663] Revert "[SIL] Add SILFunctionType flag for async." This reverts commit 9b8828848d3ed5a5ff90808146d008c94e3ac899. --- include/swift/AST/Types.h | 8 ++- lib/AST/ASTContext.cpp | 6 +-- lib/AST/ASTDemangler.cpp | 3 +- lib/AST/ASTPrinter.cpp | 1 - lib/AST/Type.cpp | 7 ++- lib/IRGen/GenProto.cpp | 2 +- lib/IRGen/LoadableByAddress.cpp | 2 - lib/SIL/IR/SILBuilder.cpp | 1 - lib/SIL/IR/SILFunctionType.cpp | 52 +++++++++---------- lib/SIL/IR/SILType.cpp | 5 +- lib/SIL/Verifier/SILVerifier.cpp | 1 - lib/SILGen/SILGen.cpp | 4 +- lib/SILGen/SILGenBridging.cpp | 2 +- lib/SILGen/SILGenExpr.cpp | 6 +-- lib/SILGen/SILGenFunction.cpp | 4 +- lib/SILGen/SILGenPoly.cpp | 6 +-- .../Differentiation/JVPCloner.cpp | 8 +-- lib/SILOptimizer/Differentiation/Thunk.cpp | 6 +-- .../Differentiation/VJPCloner.cpp | 8 +-- .../ExistentialTransform.cpp | 2 +- .../FunctionSignatureOpts.cpp | 9 ++-- lib/SILOptimizer/IPO/CapturePromotion.cpp | 5 +- lib/SILOptimizer/IPO/ClosureSpecializer.cpp | 2 +- .../Mandatory/Differentiation.cpp | 11 ++-- .../Transforms/AllocBoxToStack.cpp | 5 +- lib/SILOptimizer/Transforms/Outliner.cpp | 4 +- .../UtilityPasses/BugReducerTester.cpp | 3 +- lib/SILOptimizer/Utils/Generics.cpp | 11 ++-- lib/Sema/TypeCheckType.cpp | 7 +-- lib/Serialization/Deserialization.cpp | 3 +- 30 files changed, 81 insertions(+), 113 deletions(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index e55c8bf7be3d5..9e6401b31aa95 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -362,12 +362,11 @@ class alignas(1 << TypeAlignInBits) TypeBase { ID : 32 ); - SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+1+2+1+1, + SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2+1+1, ExtInfoBits : NumSILExtInfoBits, HasClangTypeInfo : 1, CalleeConvention : 3, HasErrorResult : 1, - IsAsync : 1, CoroutineKind : 2, HasInvocationSubs : 1, HasPatternSubs : 1 @@ -3980,7 +3979,7 @@ class SILFunctionType final + 1); } - SILFunctionType(GenericSignature genericSig, ExtInfo ext, bool isAsync, + SILFunctionType(GenericSignature genericSig, ExtInfo ext, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3994,8 +3993,7 @@ class SILFunctionType final public: static CanSILFunctionType - get(GenericSignature genericSig, ExtInfo ext, bool isAsync, - SILCoroutineKind coroutineKind, + get(GenericSignature genericSig, ExtInfo ext, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef interfaceParams, ArrayRef interfaceYields, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f3ee9197874a9..6aa37233e8809 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3300,7 +3300,6 @@ void SILFunctionType::Profile( SILFunctionType::SILFunctionType( GenericSignature genericSig, ExtInfo ext, - bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3326,7 +3325,6 @@ SILFunctionType::SILFunctionType( "Bits were dropped!"); static_assert(SILExtInfoBuilder::NumMaskBits == NumSILExtInfoBits, "ExtInfo and SILFunctionTypeBitfields must agree on bit size"); - Bits.SILFunctionType.IsAsync = isAsync; Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind); NumParameters = params.size(); if (coroutineKind == SILCoroutineKind::None) { @@ -3470,7 +3468,7 @@ CanSILBlockStorageType SILBlockStorageType::get(CanType captureType) { CanSILFunctionType SILFunctionType::get( GenericSignature genericSig, - ExtInfo ext, bool isAsync, SILCoroutineKind coroutineKind, + ExtInfo ext, SILCoroutineKind coroutineKind, ParameterConvention callee, ArrayRef params, ArrayRef yields, @@ -3537,7 +3535,7 @@ CanSILFunctionType SILFunctionType::get( } auto fnType = - new (mem) SILFunctionType(genericSig, ext, isAsync, coroutineKind, callee, + new (mem) SILFunctionType(genericSig, ext, coroutineKind, callee, params, yields, normalResults, errorResult, patternSubs, invocationSubs, ctx, properties, witnessMethodConformance); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 6e44fd70da0ef..44d32c84a7a7d 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -558,8 +558,7 @@ Type ASTBuilder::createImplFunctionType( auto conv = getResultConvention(errorResult->getConvention()); funcErrorResult.emplace(type, conv); } - return SILFunctionType::get(genericSig, einfo, - /*isAsync*/ false, funcCoroutineKind, + return SILFunctionType::get(genericSig, einfo, funcCoroutineKind, funcCalleeConvention, funcParams, funcYields, funcResults, funcErrorResult, SubstitutionMap(), SubstitutionMap(), Ctx); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index ed03d9a2c35c0..aff1100a37bf9 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4277,7 +4277,6 @@ class TypePrinter : public TypeVisitor { void visitSILFunctionType(SILFunctionType *T) { printSILCoroutineKind(T->getCoroutineKind()); - printSILAsyncAttr(T->isAsync()); printFunctionExtInfo(T->getASTContext(), T->getExtInfo(), T->getWitnessMethodConformanceOrInvalid()); printCalleeConvention(T->getCalleeConvention()); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index bc7d9b780b659..f26c9e39182af 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4378,7 +4378,6 @@ case TypeKind::Id: return SILFunctionType::get( fnTy->getInvocationGenericSignature(), fnTy->getExtInfo(), - fnTy->isAsync(), fnTy->getCoroutineKind(), fnTy->getCalleeConvention(), transInterfaceParams, @@ -5372,7 +5371,7 @@ SILFunctionType::withInvocationSubstitutions(SubstitutionMap subs) const { assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getInvocationGenericSignature()); return SILFunctionType::get(getInvocationGenericSignature(), - getExtInfo(), isAsync(), getCoroutineKind(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), @@ -5390,7 +5389,7 @@ SILFunctionType::withPatternSubstitutions(SubstitutionMap subs) const { assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getPatternGenericSignature()); return SILFunctionType::get(getInvocationGenericSignature(), - getExtInfo(), isAsync(), getCoroutineKind(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), @@ -5409,7 +5408,7 @@ SILFunctionType::withPatternSpecialization(CanGenericSignature sig, assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getSubstGenericSignature()); return SILFunctionType::get(sig, - getExtInfo(), isAsync(), getCoroutineKind(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 6282e402545c8..2795553485a5a 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3056,7 +3056,7 @@ GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, // Construct a representative function type. auto generics = ncGenerics.getCanonicalSignature(); auto fnType = SILFunctionType::get(generics, SILFunctionType::ExtInfo(), - /*isAsync*/ false, SILCoroutineKind::None, + SILCoroutineKind::None, /*callee*/ ParameterConvention::Direct_Unowned, /*params*/ {}, /*yields*/ {}, /*results*/ {}, /*error*/ None, diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 6d798d7ea8131..2a509cbfeeb89 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -297,7 +297,6 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env, auto newFnType = SILFunctionType::get( fnType->getInvocationGenericSignature(), fnType->getExtInfo(), - fnType->isAsync(), fnType->getCoroutineKind(), fnType->getCalleeConvention(), newParams, @@ -2362,7 +2361,6 @@ static bool rewriteFunctionReturn(StructLoweringState &pass) { auto NewTy = SILFunctionType::get( loweredTy->getSubstGenericSignature(), loweredTy->getExtInfo(), - loweredTy->isAsync(), loweredTy->getCoroutineKind(), loweredTy->getCalleeConvention(), loweredTy->getParameters(), diff --git a/lib/SIL/IR/SILBuilder.cpp b/lib/SIL/IR/SILBuilder.cpp index d6a876037c0b9..c925cc83bb737 100644 --- a/lib/SIL/IR/SILBuilder.cpp +++ b/lib/SIL/IR/SILBuilder.cpp @@ -107,7 +107,6 @@ SILType SILBuilder::getPartialApplyResultType( auto appliedFnType = SILFunctionType::get(nullptr, extInfo, - FTI->isAsync(), FTI->getCoroutineKind(), calleeConvention, newParams, diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 0e50bdd34f8e4..2d3e10054313d 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -94,7 +94,6 @@ CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const { : CanGenericSignature(); return SILFunctionType::get(signature, getExtInfo(), - isAsync(), getCoroutineKind(), getCalleeConvention(), params, yields, results, errorResult, @@ -288,11 +287,11 @@ SILFunctionType::getWithDifferentiability(DifferentiabilityKind kind, } auto newExtInfo = getExtInfo().intoBuilder().withDifferentiabilityKind(kind).build(); - return get(getInvocationGenericSignature(), newExtInfo, isAsync(), - getCoroutineKind(), getCalleeConvention(), newParameters, - getYields(), newResults, getOptionalErrorResult(), - getPatternSubstitutions(), getInvocationSubstitutions(), - getASTContext(), getWitnessMethodConformanceOrInvalid()); + return get(getInvocationGenericSignature(), newExtInfo, getCoroutineKind(), + getCalleeConvention(), newParameters, getYields(), newResults, + getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationSubstitutions(), getASTContext(), + getWitnessMethodConformanceOrInvalid()); } CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { @@ -312,9 +311,9 @@ CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { newResults.push_back(result.getWithDifferentiability( SILResultDifferentiability::DifferentiableOrNotApplicable)); return SILFunctionType::get( - getInvocationGenericSignature(), nondiffExtInfo, isAsync(), - getCoroutineKind(), getCalleeConvention(), newParams, getYields(), - newResults, getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationGenericSignature(), nondiffExtInfo, getCoroutineKind(), + getCalleeConvention(), newParams, getYields(), newResults, + getOptionalErrorResult(), getPatternSubstitutions(), getInvocationSubstitutions(), getASTContext()); } @@ -503,9 +502,9 @@ static CanSILFunctionType getAutoDiffDifferentialType( llvm::makeArrayRef(substConformances)); } return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), /*isAsync*/ false, - SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, - differentialParams, {}, differentialResults, None, substitutions, + GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, differentialParams, {}, + differentialResults, None, substitutions, /*invocationSubstitutions*/ SubstitutionMap(), ctx); } @@ -682,9 +681,9 @@ static CanSILFunctionType getAutoDiffPullbackType( llvm::makeArrayRef(substConformances)); } return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), /*isAsync*/ false, - SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, - pullbackParams, {}, pullbackResults, None, substitutions, + GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, pullbackParams, {}, + pullbackResults, None, substitutions, /*invocationSubstitutions*/ SubstitutionMap(), ctx); } @@ -738,7 +737,7 @@ static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( constrainedInvocationGenSig->areAllParamsConcrete() ? GenericSignature() : constrainedInvocationGenSig, - original->getExtInfo(), original->isAsync(), original->getCoroutineKind(), + original->getExtInfo(), original->getCoroutineKind(), original->getCalleeConvention(), newParameters, original->getYields(), newResults, original->getOptionalErrorResult(), /*patternSubstitutions*/ SubstitutionMap(), @@ -829,7 +828,6 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( // cache and return. cachedResult = SILFunctionType::get( constrainedOriginalFnTy->getSubstGenericSignature(), extInfo, - constrainedOriginalFnTy->isAsync(), constrainedOriginalFnTy->getCoroutineKind(), constrainedOriginalFnTy->getCalleeConvention(), newParameters, constrainedOriginalFnTy->getYields(), newResults, @@ -915,9 +913,9 @@ CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( for (auto &res : getResults()) newParameters.push_back(getParameterInfoForOriginalResult(res)); return SILFunctionType::get( - getInvocationGenericSignature(), getExtInfo(), isAsync(), - getCoroutineKind(), getCalleeConvention(), newParameters, getYields(), - newResults, getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), + getCalleeConvention(), newParameters, getYields(), newResults, + getOptionalErrorResult(), getPatternSubstitutions(), /*invocationSubstitutions*/ {}, getASTContext()); } @@ -991,8 +989,7 @@ Lowering::adjustFunctionType(CanSILFunctionType type, return type; return SILFunctionType::get(type->getInvocationGenericSignature(), - extInfo, type->isAsync(), - type->getCoroutineKind(), callee, + extInfo, type->getCoroutineKind(), callee, type->getParameters(), type->getYields(), type->getResults(), type->getOptionalErrorResult(), @@ -1019,9 +1016,9 @@ CanSILFunctionType SILFunctionType::getWithExtInfo(ExtInfo newExt) { : Lowering::DefaultThickCalleeConvention) : ParameterConvention::Direct_Unowned); - return get(getInvocationGenericSignature(), newExt, isAsync(), - getCoroutineKind(), calleeConvention, getParameters(), getYields(), - getResults(), getOptionalErrorResult(), getPatternSubstitutions(), + return get(getInvocationGenericSignature(), newExt, getCoroutineKind(), + calleeConvention, getParameters(), getYields(), getResults(), + getOptionalErrorResult(), getPatternSubstitutions(), getInvocationSubstitutions(), getASTContext(), getWitnessMethodConformanceOrInvalid()); } @@ -2169,8 +2166,7 @@ static CanSILFunctionType getSILFunctionType( } } - return SILFunctionType::get(genericSig, silExtInfo, - substFnInterfaceType->isAsync(), coroutineKind, + return SILFunctionType::get(genericSig, silExtInfo, coroutineKind, calleeConvention, inputs, yields, results, errorResult, substitutions, SubstitutionMap(), @@ -3760,7 +3756,7 @@ class SILTypeSubstituter : ? origType->getInvocationGenericSignature() : nullptr; - return SILFunctionType::get(genericSig, extInfo, origType->isAsync(), + return SILFunctionType::get(genericSig, extInfo, origType->getCoroutineKind(), origType->getCalleeConvention(), substParams, substYields, substResults, substErrorResult, diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index 28f323ccf8769..48ca1e5cbc47d 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -671,10 +671,9 @@ TypeBase::replaceSubstitutedSILFunctionTypesWithUnsubstituted(SILModule &M) cons if (!didChange) return sft; - + return SILFunctionType::get(sft->getInvocationGenericSignature(), - sft->getExtInfo(), sft->isAsync(), - sft->getCoroutineKind(), + sft->getExtInfo(), sft->getCoroutineKind(), sft->getCalleeConvention(), newParams, newYields, newResults, newErrorResult, diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 3f27e20fe801d..c2f3de4038027 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -3003,7 +3003,6 @@ class SILVerifier : public SILVerifierBase { auto fnTy = SILFunctionType::get(nullptr, methodTy->getExtInfo(), - methodTy->isAsync(), methodTy->getCoroutineKind(), methodTy->getCalleeConvention(), dynParams, diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index dffd4c3b8dfdf..cd36b343f0e58 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -419,7 +419,7 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, /*clangFunctionType*/ nullptr) .build(); - auto functionTy = SILFunctionType::get(sig, extInfo, /*isAsync*/ false, + auto functionTy = SILFunctionType::get(sig, extInfo, SILCoroutineKind::YieldOnce, ParameterConvention::Direct_Unowned, params, @@ -482,7 +482,7 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) { }; CanSILFunctionType topLevelType = SILFunctionType::get(nullptr, extInfo, - /*isAsync*/ false, SILCoroutineKind::None, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, SILResultInfo(Int32Ty, diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index a013d5b188baa..7eedc3b1975fa 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -578,7 +578,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, } auto invokeTy = SILFunctionType::get( - genericSig, extInfo, /*isAsync*/ false, SILCoroutineKind::None, + genericSig, extInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, blockInterfaceTy->getResults(), blockInterfaceTy->getOptionalErrorResult(), diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 8ef8f36c118ee..cb8273d129e1e 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2750,7 +2750,6 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, return SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, result, None, @@ -2897,10 +2896,9 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredInterfaceType() ->getCanonicalType(), ParameterConvention::Direct_Unowned}); - + return SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, {}, None, @@ -3083,7 +3081,6 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, @@ -3258,7 +3255,6 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 7f6cf2516db66..d9acdc516f6ac 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -602,7 +602,6 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { SILFunctionType::ExtInfo() .withRepresentation(SILFunctionType::Representation:: CFunctionPointer), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, SILParameterInfo(anyObjectMetaTy, @@ -698,8 +697,7 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { // has an overlay to fix the type of argv. .withRepresentation(SILFunctionType::Representation::Thin) .build(), - /*isAsync*/ false, SILCoroutineKind::None, - ParameterConvention::Direct_Unowned, argTypes, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, argTypes, /*yields*/ {}, SILResultInfo(argc->getType().getASTType(), ResultConvention::Unowned), /*error result*/ None, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 110edd25ba171..0ee11d74f6439 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -3245,9 +3245,9 @@ CanSILFunctionType SILGenFunction::buildThunkType( // The type of the thunk function. return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->isAsync(), - expectedType->getCoroutineKind(), ParameterConvention::Direct_Unowned, - interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, + genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), + ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, + interfaceResults, interfaceErrorResult, expectedType->getPatternSubstitutions(), SubstitutionMap(), getASTContext()); } diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index f2e1d04aea635..d7b8caa102e53 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -1587,10 +1587,10 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto *diffGenericEnv = diffGenericSig ? diffGenericSig->getGenericEnvironment() : nullptr; auto diffType = SILFunctionType::get( - diffGenericSig, origTy->getExtInfo(), origTy->isAsync(), - origTy->getCoroutineKind(), origTy->getCalleeConvention(), dfParams, {}, - dfResults, None, origTy->getPatternSubstitutions(), - origTy->getInvocationSubstitutions(), original->getASTContext()); + diffGenericSig, origTy->getExtInfo(), origTy->getCoroutineKind(), + origTy->getCalleeConvention(), dfParams, {}, dfResults, None, + origTy->getPatternSubstitutions(), origTy->getInvocationSubstitutions(), + original->getASTContext()); SILOptFunctionBuilder fb(context.getTransform()); auto linkage = jvp->isSerialized() ? SILLinkage::Public : SILLinkage::Hidden; diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index bd1817c6f3994..820805fff06d9 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -242,9 +242,9 @@ CanSILFunctionType buildThunkType(SILFunction *fn, // The type of the thunk function. return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->isAsync(), - expectedType->getCoroutineKind(), ParameterConvention::Direct_Unowned, - interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, + genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), + ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, + interfaceResults, interfaceErrorResult, expectedType->getPatternSubstitutions(), SubstitutionMap(), fn->getASTContext()); } diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index dc0d915148e20..7279ce914d83c 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -892,10 +892,10 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { auto *pbGenericEnv = pbGenericSig ? pbGenericSig->getGenericEnvironment() : nullptr; auto pbType = SILFunctionType::get( - pbGenericSig, origTy->getExtInfo(), origTy->isAsync(), - origTy->getCoroutineKind(), origTy->getCalleeConvention(), pbParams, {}, - adjResults, None, origTy->getPatternSubstitutions(), - origTy->getInvocationSubstitutions(), original->getASTContext()); + pbGenericSig, origTy->getExtInfo(), origTy->getCoroutineKind(), + origTy->getCalleeConvention(), pbParams, {}, adjResults, None, + origTy->getPatternSubstitutions(), origTy->getInvocationSubstitutions(), + original->getASTContext()); SILOptFunctionBuilder fb(context.getTransform()); auto linkage = vjp->isSerialized() ? SILLinkage::Public : SILLinkage::Private; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 839810a36223d..66617c63b0c24 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -403,7 +403,7 @@ ExistentialTransform::createExistentialSpecializedFunctionType() { /// Return the new signature. return SILFunctionType::get( - NewGenericSig, ExtInfo, FTy->isAsync(), FTy->getCoroutineKind(), + NewGenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(), InterfaceParams, FTy->getYields(), FTy->getResults(), InterfaceErrorResult, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 328f55ab17ee9..7d1f34ea07cc4 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -408,11 +408,10 @@ FunctionSignatureTransformDescriptor::createOptimizedSILFunctionType() { UsesGenerics ? FTy->getInvocationGenericSignature() : nullptr; return SILFunctionType::get( - GenericSig, ExtInfo, FTy->isAsync(), FTy->getCoroutineKind(), - FTy->getCalleeConvention(), InterfaceParams, InterfaceYields, - InterfaceResults, InterfaceErrorResult, FTy->getPatternSubstitutions(), - SubstitutionMap(), F->getModule().getASTContext(), - witnessMethodConformance); + GenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(), + InterfaceParams, InterfaceYields, InterfaceResults, InterfaceErrorResult, + FTy->getPatternSubstitutions(), SubstitutionMap(), + F->getModule().getASTContext(), witnessMethodConformance); } /// Compute what the function interface will look like based on the diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp index ee4f6badc8505..37533fef306fc 100644 --- a/lib/SILOptimizer/IPO/CapturePromotion.cpp +++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp @@ -428,9 +428,8 @@ ClosureCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, // Create the thin function type for the cloned closure. auto ClonedTy = SILFunctionType::get( OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), - OrigFTI->isAsync(), OrigFTI->getCoroutineKind(), - OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, - OrigFTI->getYields(), OrigFTI->getResults(), + OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), + ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 137054e99ec18..05ab7bcaf6f10 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -670,7 +670,7 @@ ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, auto ClonedTy = SILFunctionType::get( ClosureUserFunTy->getInvocationGenericSignature(), ExtInfo, - ClosureUserFunTy->isAsync(), ClosureUserFunTy->getCoroutineKind(), + ClosureUserFunTy->getCoroutineKind(), ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList, ClosureUserFunTy->getYields(), ClosureUserFunTy->getResults(), ClosureUserFunTy->getOptionalErrorResult(), diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index a2e60703933bf..083f840e892e7 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -872,8 +872,7 @@ static void emitFatalError(ADContext &context, SILFunction *f, // Fatal error function must have type `@convention(thin) () -> Never`. auto fatalErrorFnType = SILFunctionType::get( /*genericSig*/ nullptr, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, - ParameterConvention::Direct_Unowned, {}, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, {}, /*interfaceYields*/ {}, neverResultInfo, /*interfaceErrorResults*/ None, {}, {}, context.getASTContext()); auto fnBuilder = SILOptFunctionBuilder(context.getTransform()); @@ -1025,10 +1024,10 @@ static SILValue promoteCurryThunkApplicationToDifferentiableFunction( auto newThunkResult = thunkResult.getWithInterfaceType(diffResultFnTy); auto thunkType = SILFunctionType::get( thunkTy->getSubstGenericSignature(), thunkTy->getExtInfo(), - thunkTy->isAsync(), thunkTy->getCoroutineKind(), - thunkTy->getCalleeConvention(), thunkTy->getParameters(), {}, - {newThunkResult}, {}, thunkTy->getPatternSubstitutions(), - thunkTy->getInvocationSubstitutions(), thunkTy->getASTContext()); + thunkTy->getCoroutineKind(), thunkTy->getCalleeConvention(), + thunkTy->getParameters(), {}, {newThunkResult}, {}, + thunkTy->getPatternSubstitutions(), thunkTy->getInvocationSubstitutions(), + thunkTy->getASTContext()); // Construct new curry thunk, returning a `@differentiable` function. SILOptFunctionBuilder fb(dt.getTransform()); diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 93571944f8312..6483b47a12a6f 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -699,9 +699,8 @@ SILFunction *PromotedParamCloner::initCloned(SILOptFunctionBuilder &FuncBuilder, // the parameters promoted. auto ClonedTy = SILFunctionType::get( OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), - OrigFTI->isAsync(), OrigFTI->getCoroutineKind(), - OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, - OrigFTI->getYields(), OrigFTI->getResults(), + OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), + ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(), OrigFTI->getPatternSubstitutions(), OrigFTI->getInvocationSubstitutions(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index 4426205c94ff0..e052a6b000f3c 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -302,7 +302,7 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { /*clangFunctionType*/ nullptr) .build(); auto FunctionType = SILFunctionType::get( - nullptr, ExtInfo, /*isAsync*/ false, SILCoroutineKind::None, + nullptr, ExtInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, /*yields*/ {}, Results, None, SubstitutionMap(), SubstitutionMap(), @@ -1203,7 +1203,7 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { SILResultInfo(BridgedReturn.getReturnType(), ResultConvention::Owned)); } auto FunctionType = SILFunctionType::get( - nullptr, ExtInfo, /*isAsync*/ false, SILCoroutineKind::None, + nullptr, ExtInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, {}, Results, None, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index 3ec8f130c3496..a8f823e584d5a 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -89,8 +89,7 @@ class BugReducerTester : public SILFunctionTransform { false /*noescape*/, DifferentiabilityKind::NonDifferentiable, nullptr /*clangFunctionType*/) .build(), - /*isAsync*/ false, SILCoroutineKind::None, - ParameterConvention::Direct_Unowned, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, ArrayRef(), ArrayRef(), ResultInfoArray, None, SubstitutionMap(), SubstitutionMap(), getFunction()->getModule().getASTContext()); diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 39dfd0c59c28f..2bde614efd66c 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -785,11 +785,10 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, // Use the new specialized generic signature. auto NewFnTy = SILFunctionType::get( - CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->isAsync(), - FnTy->getCoroutineKind(), FnTy->getCalleeConvention(), - FnTy->getParameters(), FnTy->getYields(), FnTy->getResults(), - FnTy->getOptionalErrorResult(), FnTy->getPatternSubstitutions(), - SubstitutionMap(), M.getASTContext(), + CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCoroutineKind(), + FnTy->getCalleeConvention(), FnTy->getParameters(), FnTy->getYields(), + FnTy->getResults(), FnTy->getOptionalErrorResult(), + FnTy->getPatternSubstitutions(), SubstitutionMap(), M.getASTContext(), FnTy->getWitnessMethodConformanceOrInvalid()); // This is an interface type. It should not have any archetypes. @@ -857,7 +856,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const { ? SubstFTy->getInvocationGenericSignature() : CanGenericSignature(); return SILFunctionType::get( - Signature, SubstFTy->getExtInfo(), SubstFTy->isAsync(), + Signature, SubstFTy->getExtInfo(), SubstFTy->getCoroutineKind(), SubstFTy->getCalleeConvention(), SpecializedParams, SpecializedYields, SpecializedResults, SubstFTy->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 864d2b926adb9..8ec5b7a9f942f 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1749,7 +1749,6 @@ namespace { Type resolveSILFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, - bool isAsync = false, SILCoroutineKind coroutineKind = SILCoroutineKind::None, SILFunctionType::ExtInfo extInfo @@ -2230,7 +2229,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, attrs.has(TAK_noescape), diffKind, nullptr) .build(); - ty = resolveSILFunctionType(fnRepr, options, isAsync, coroutineKind, extInfo, + ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, calleeConvention, witnessMethodProtocol); if (!ty || ty->hasError()) return ty; @@ -2845,7 +2844,6 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, - bool isAsync, SILCoroutineKind coroutineKind, SILFunctionType::ExtInfo extInfo, ParameterConvention callee, @@ -3040,8 +3038,7 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, "found witness_method without matching conformance"); } - return SILFunctionType::get(genericSig, extInfo, isAsync, - coroutineKind, callee, + return SILFunctionType::get(genericSig, extInfo, coroutineKind, callee, interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, interfacePatternSubs, invocationSubs, diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 0bb3cef17922d..a2b83b1faaf00 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5568,8 +5568,7 @@ class TypeDeserializer { if (!patternSubsOrErr) return patternSubsOrErr.takeError(); - return SILFunctionType::get(invocationSig, extInfo, - async, coroutineKind.getValue(), + return SILFunctionType::get(invocationSig, extInfo, coroutineKind.getValue(), calleeConvention.getValue(), allParams, allYields, allResults, errorResult, From 5d813f38ecc944e360c72ddad293b706532ce404 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 25 Aug 2020 12:58:53 -0700 Subject: [PATCH 325/663] Revert "[SIL] Add flag to SILFunctionType::Profile for async." This reverts commit b8976a3ec5c10d4b50e1a007f743bc48cc34fae1. --- include/swift/AST/Types.h | 4 ++-- lib/AST/ASTContext.cpp | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 9e6401b31aa95..21e9a5ccd37f6 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -4575,14 +4575,14 @@ class SILFunctionType final void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInvocationGenericSignature(), - getExtInfo(), isAsync(), getCoroutineKind(), getCalleeConvention(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), getWitnessMethodConformanceOrInvalid(), getPatternSubstitutions(), getInvocationSubstitutions()); } static void Profile(llvm::FoldingSetNodeID &ID, GenericSignature genericSig, ExtInfo info, - bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, + SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, ArrayRef yields, ArrayRef results, Optional errorResult, ProtocolConformanceRef conformance, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 6aa37233e8809..633527ccf7735 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3260,7 +3260,6 @@ void SILFunctionType::Profile( llvm::FoldingSetNodeID &id, GenericSignature genericParams, ExtInfo info, - bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3274,7 +3273,6 @@ void SILFunctionType::Profile( auto infoKey = info.getFuncAttrKey(); id.AddInteger(infoKey.first); id.AddPointer(infoKey.second); - id.AddBoolean(isAsync); id.AddInteger(unsigned(coroutineKind)); id.AddInteger(unsigned(calleeConvention)); id.AddInteger(params.size()); @@ -3486,8 +3484,8 @@ CanSILFunctionType SILFunctionType::get( invocationSubs = invocationSubs.getCanonical(); llvm::FoldingSetNodeID id; - SILFunctionType::Profile(id, genericSig, ext, isAsync, coroutineKind, callee, - params, yields, normalResults, errorResult, + SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params, + yields, normalResults, errorResult, witnessMethodConformance, patternSubs, invocationSubs); From 78159c83f76a7871445d307031865ac33ec7df98 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 25 Aug 2020 09:57:21 -0700 Subject: [PATCH 326/663] [Explicit Module Builds] Handle #canImport in the dependency scanner by adding scanner "loaders" to the ASTContext. --- .../Serialization/ModuleDependencyScanner.h | 110 ++++++++++ lib/Frontend/Frontend.cpp | 30 ++- lib/Serialization/ModuleDependencyScanner.cpp | 198 ++++++------------ .../can_import_placeholder.swift | 55 +++++ 4 files changed, 255 insertions(+), 138 deletions(-) create mode 100644 include/swift/Serialization/ModuleDependencyScanner.h create mode 100644 test/ScanDependencies/can_import_placeholder.swift diff --git a/include/swift/Serialization/ModuleDependencyScanner.h b/include/swift/Serialization/ModuleDependencyScanner.h new file mode 100644 index 0000000000000..07006770d8f49 --- /dev/null +++ b/include/swift/Serialization/ModuleDependencyScanner.h @@ -0,0 +1,110 @@ +//===--- ModuleDependencyScanner.h - Import Swift modules --------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/ASTContext.h" +#include "swift/Frontend/ModuleInterfaceLoader.h" +#include "swift/Serialization/SerializedModuleLoader.h" + +namespace swift { + /// A module "loader" that looks for .swiftinterface and .swiftmodule files + /// for the purpose of determining dependencies, but does not attempt to + /// load the module files. + class ModuleDependencyScanner : public SerializedModuleLoaderBase { + /// The module we're scanning dependencies of. + Identifier moduleName; + + /// Scan the given interface file to determine dependencies. + llvm::ErrorOr scanInterfaceFile( + Twine moduleInterfacePath, bool isFramework); + + InterfaceSubContextDelegate &astDelegate; + public: + Optional dependencies; + + /// Describes the kind of dependencies this scanner is able to identify + ModuleDependenciesKind dependencyKind; + + ModuleDependencyScanner( + ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, + InterfaceSubContextDelegate &astDelegate, + ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift) + : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, + /*IgnoreSwiftSourceInfoFile=*/true), + moduleName(moduleName), astDelegate(astDelegate), + dependencyKind(dependencyKind) {} + + std::error_code findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; + + virtual void collectVisibleTopLevelModuleNames( + SmallVectorImpl &names) const override { + llvm_unreachable("Not used"); + } + }; + + /// A ModuleLoader that loads placeholder dependency module stubs specified in + /// -placeholder-dependency-module-map-file + /// This loader is used only in dependency scanning to inform the scanner that a + /// set of modules constitute placeholder dependencies that are not visible to the + /// scanner but will nevertheless be provided by the scanner's clients. + /// This "loader" will not attempt to load any module files. + class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner { + /// Scan the given placeholder module map + void parsePlaceholderModuleMap(StringRef fileName) { + ExplicitModuleMapParser parser(Allocator); + auto result = + parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap); + if (result == std::errc::invalid_argument) { + Ctx.Diags.diagnose(SourceLoc(), + diag::placeholder_dependency_module_map_corrupted, + fileName); + } + else if (result == std::errc::no_such_file_or_directory) { + Ctx.Diags.diagnose(SourceLoc(), + diag::placeholder_dependency_module_map_missing, + fileName); + } + } + + llvm::StringMap PlaceholderDependencyModuleMap; + llvm::BumpPtrAllocator Allocator; + + public: + PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, + Identifier moduleName, + StringRef PlaceholderDependencyModuleMap, + InterfaceSubContextDelegate &astDelegate) + : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, + ModuleDependenciesKind::SwiftPlaceholder) { + + // FIXME: Find a better place for this map to live, to avoid + // doing the parsing on every module. + if (!PlaceholderDependencyModuleMap.empty()) { + parsePlaceholderModuleMap(PlaceholderDependencyModuleMap); + } + } + + std::error_code findModuleFilesInDirectory( + AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; + }; +} diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 7e000a0b6a563..96f73546529c6 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -33,6 +33,7 @@ #include "swift/SILOptimizer/Utils/Generics.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Serialization/SerializedModuleLoader.h" +#include "swift/Serialization/ModuleDependencyScanner.h" #include "swift/Strings.h" #include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" @@ -520,9 +521,36 @@ bool CompilerInstance::setUpModuleLoaders() { this->DefaultSerializedLoader = ISML.get(); Context->addModuleLoader(std::move(ISML)); } - + Context->addModuleLoader(std::move(clangImporter), /*isClang*/ true); + // When scanning for dependencies, we must add the scanner loaders in order to handle + // ASTContext operations such as canImportModule + if (Invocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::ScanDependencies) { + auto ModuleCachePath = getModuleCachePathFromClang(Context + ->getClangModuleLoader()->getClangInstance()); + auto &FEOpts = Invocation.getFrontendOptions(); + ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); + InterfaceSubContextDelegateImpl ASTDelegate(Context->SourceMgr, Context->Diags, + Context->SearchPathOpts, Context->LangOpts, + LoaderOpts, + Context->getClangModuleLoader(), + /*buildModuleCacheDirIfAbsent*/false, + ModuleCachePath, + FEOpts.PrebuiltModuleCachePath, + FEOpts.SerializeModuleInterfaceDependencyHashes, + FEOpts.shouldTrackSystemDependencies()); + auto mainModuleName = Context->getIdentifier(FEOpts.ModuleName); + std::unique_ptr PSMS = + std::make_unique(*Context, + MLM, + mainModuleName, + Context->SearchPathOpts.PlaceholderDependencyModuleMap, + ASTDelegate); + Context->addModuleLoader(std::move(PSMS)); + } + return false; } diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index ab06b6189060f..fbe77f062b9b6 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -19,157 +19,81 @@ #include "swift/Basic/FileTypes.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Serialization/SerializedModuleLoader.h" +#include "swift/Serialization/ModuleDependencyScanner.h" #include "swift/Subsystems.h" using namespace swift; using llvm::ErrorOr; -namespace { -/// A module "loader" that looks for .swiftinterface and .swiftmodule files -/// for the purpose of determining dependencies, but does not attempt to -/// load the module files. -class ModuleDependencyScanner : public SerializedModuleLoaderBase { - /// The module we're scanning dependencies of. - Identifier moduleName; - - /// Scan the given interface file to determine dependencies. - ErrorOr scanInterfaceFile( - Twine moduleInterfacePath, bool isFramework); - - InterfaceSubContextDelegate &astDelegate; -public: - Optional dependencies; - - /// Describes the kind of dependencies this scanner is able to identify - ModuleDependenciesKind dependencyKind; - - ModuleDependencyScanner( - ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, - InterfaceSubContextDelegate &astDelegate, - ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift) - : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, - /*IgnoreSwiftSourceInfoFile=*/true), - moduleName(moduleName), astDelegate(astDelegate), - dependencyKind(dependencyKind) {} - - virtual std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer, - bool IsFramework) override { - using namespace llvm::sys; - - auto &fs = *Ctx.SourceMgr.getFileSystem(); - - auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile); - auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile); - - if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) { - if (fs.exists(ModPath)) { - // The module file will be loaded directly. - auto dependencies = scanModuleFile(ModPath); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); - return std::error_code(); - } - return dependencies.getError(); - } else { - return std::make_error_code(std::errc::no_such_file_or_directory); +std::error_code ModuleDependencyScanner::findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + using namespace llvm::sys; + + auto &fs = *Ctx.SourceMgr.getFileSystem(); + + auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile); + auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile); + + if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) { + if (fs.exists(ModPath)) { + // The module file will be loaded directly. + auto dependencies = scanModuleFile(ModPath); + if (dependencies) { + this->dependencies = std::move(dependencies.get()); + return std::error_code(); } + return dependencies.getError(); + } else { + return std::make_error_code(std::errc::no_such_file_or_directory); } - assert(fs.exists(InPath)); - // Use the private interface file if exits. - auto PrivateInPath = - BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile); - if (fs.exists(PrivateInPath)) { - InPath = PrivateInPath; - } - auto dependencies = scanInterfaceFile(InPath, IsFramework); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); - return std::error_code(); - } - - return dependencies.getError(); } - - virtual void collectVisibleTopLevelModuleNames( - SmallVectorImpl &names) const override { - llvm_unreachable("Not used"); + assert(fs.exists(InPath)); + // Use the private interface file if exits. + auto PrivateInPath = + BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile); + if (fs.exists(PrivateInPath)) { + InPath = PrivateInPath; } -}; - -/// A ModuleLoader that loads placeholder dependency module stubs specified in -/// -placeholder-dependency-module-map-file -/// This loader is used only in dependency scanning to inform the scanner that a -/// set of modules constitute placeholder dependencies that are not visible to the -/// scanner but will nevertheless be provided by the scanner's clients. -/// This "loader" will not attempt to load any module files. -class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner { - /// Scan the given placeholder module map - void parsePlaceholderModuleMap(StringRef fileName) { - ExplicitModuleMapParser parser(Allocator); - auto result = - parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap); - if (result == std::errc::invalid_argument) { - Ctx.Diags.diagnose(SourceLoc(), - diag::placeholder_dependency_module_map_corrupted, - fileName); - } - else if (result == std::errc::no_such_file_or_directory) { - Ctx.Diags.diagnose(SourceLoc(), - diag::placeholder_dependency_module_map_missing, - fileName); - } + auto dependencies = scanInterfaceFile(InPath, IsFramework); + if (dependencies) { + this->dependencies = std::move(dependencies.get()); + return std::error_code(); } - llvm::StringMap PlaceholderDependencyModuleMap; - llvm::BumpPtrAllocator Allocator; - -public: - PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, - Identifier moduleName, - StringRef PlaceholderDependencyModuleMap, - InterfaceSubContextDelegate &astDelegate) - : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, - ModuleDependenciesKind::SwiftPlaceholder) { - - // FIXME: Find a better place for this map to live, to avoid - // doing the parsing on every module. - if (!PlaceholderDependencyModuleMap.empty()) { - parsePlaceholderModuleMap(PlaceholderDependencyModuleMap); - } - } + return dependencies.getError(); +} - std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer, - bool IsFramework) override { - StringRef moduleName = ModuleID.Item.str(); - auto it = PlaceholderDependencyModuleMap.find(moduleName); - // If no placeholder module stub path is given matches the name, return with an - // error code. - if (it == PlaceholderDependencyModuleMap.end()) { - return std::make_error_code(std::errc::not_supported); - } - auto &moduleInfo = it->getValue(); - assert(!moduleInfo.moduleBuffer && - "Placeholder dependency module stubs cannot have an associated buffer"); - auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub( - moduleInfo.modulePath, moduleInfo.moduleDocPath, - moduleInfo.moduleSourceInfoPath); - this->dependencies = std::move(dependencies); - return std::error_code{}; +std::error_code PlaceholderSwiftModuleScanner::findModuleFilesInDirectory( + AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + StringRef moduleName = ModuleID.Item.str(); + auto it = PlaceholderDependencyModuleMap.find(moduleName); + // If no placeholder module stub path is given matches the name, return with an + // error code. + if (it == PlaceholderDependencyModuleMap.end()) { + return std::make_error_code(std::errc::not_supported); } -}; -} // namespace + auto &moduleInfo = it->getValue(); + assert(!moduleInfo.moduleBuffer && + "Placeholder dependency module stubs cannot have an associated buffer"); + + auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub( + moduleInfo.modulePath, moduleInfo.moduleDocPath, + moduleInfo.moduleSourceInfoPath); + this->dependencies = std::move(dependencies); + return std::error_code{}; +} static std::vector getCompiledCandidates(ASTContext &ctx, StringRef moduleName, diff --git a/test/ScanDependencies/can_import_placeholder.swift b/test/ScanDependencies/can_import_placeholder.swift new file mode 100644 index 0000000000000..8b64644fc9a9b --- /dev/null +++ b/test/ScanDependencies/can_import_placeholder.swift @@ -0,0 +1,55 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/inputs + +// RUN: echo "[{" > %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SomeExternalModule\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/t/inputs/SomeExternalModule.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}]" >> %/t/inputs/map.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json + +// REQUIRES: executable_test +// REQUIRES: objc_interop +#if canImport(SomeExternalModule) +import SomeExternalModule +#endif + +// CHECK: "mainModuleName": "deps" + +/// --------Main module +// CHECK-LABEL: "modulePath": "deps.swiftmodule", +// CHECK-NEXT: sourceFiles +// CHECK-NEXT: can_import_placeholder.swift + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "swiftPlaceholder": "SomeExternalModule" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "Swift" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "SwiftOnoneSupport" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "F" +// CHECK-NEXT: } +// CHECK-NEXT: ], + From 4b9cf31ba0dd8cc00aa9385507f6269e65230fe6 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 11 Aug 2020 17:41:19 -0700 Subject: [PATCH 327/663] Add a callback to swift::reflection::MemoryReader that allows LLDB to provide swift::reflection::TypeInfo for (Clang-)imported non-Objective-C types. This is needed to reflect on the size mixed Swift / Clang types, when no type metadata is available for the C types. This is a necessary ingredient for the TypeRef-based Swift context in LLDB. Because we do not have reflection metadata for pure C types in Swift, reflection cannot compute TypeInfo for NominalTypeRefs for those types. By providing this callback, LLDB can supply this information for DWARF, and reflection can compute TypeInfos for mixed Swift/C types. --- include/swift/Demangling/TypeDecoder.h | 5 +- include/swift/Reflection/ReflectionContext.h | 49 +++++---- include/swift/Reflection/TypeLowering.h | 12 ++- include/swift/Reflection/TypeRef.h | 4 +- include/swift/Reflection/TypeRefBuilder.h | 10 +- include/swift/Remote/MemoryReader.h | 6 +- include/swift/Remote/TypeInfoProvider.h | 39 +++++++ stdlib/public/Reflection/TypeLowering.cpp | 102 +++++++++++------- stdlib/public/Reflection/TypeRef.cpp | 6 +- stdlib/public/Reflection/TypeRefBuilder.cpp | 7 +- .../SwiftRemoteMirror/SwiftRemoteMirror.cpp | 30 +++--- .../swift-reflection-dump.cpp | 29 ++--- 12 files changed, 185 insertions(+), 114 deletions(-) create mode 100644 include/swift/Remote/TypeInfoProvider.h diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index e591e978dccd1..fbc328e3d32b1 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -328,9 +328,8 @@ class TypeDecoder { BuilderType &Builder; - public: - explicit TypeDecoder(BuilderType &Builder) - : Builder(Builder) {} +public: + explicit TypeDecoder(BuilderType &Builder) : Builder(Builder) {} /// Given a demangle tree, attempt to turn it into a type. BuiltType decodeMangledType(NodePointer Node) { diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 6fc3df0882f5f..9e26669aa8f38 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -680,7 +680,9 @@ class ReflectionContext /// Return a description of the layout of a class instance with the given /// metadata as its isa pointer. - const TypeInfo *getMetadataTypeInfo(StoredPointer MetadataAddress) { + const TypeInfo * + getMetadataTypeInfo(StoredPointer MetadataAddress, + remote::TypeInfoProvider *ExternalTypeInfo) { // See if we cached the layout already auto found = Cache.find(MetadataAddress); if (found != Cache.end()) @@ -702,7 +704,7 @@ class ReflectionContext // Perform layout if (start) - TI = TC.getClassInstanceTypeInfo(TR, *start); + TI = TC.getClassInstanceTypeInfo(TR, *start, ExternalTypeInfo); break; } @@ -718,7 +720,9 @@ class ReflectionContext /// Return a description of the layout of a class instance with the given /// metadata as its isa pointer. - const TypeInfo *getInstanceTypeInfo(StoredPointer ObjectAddress) { + const TypeInfo * + getInstanceTypeInfo(StoredPointer ObjectAddress, + remote::TypeInfoProvider *ExternalTypeInfo) { auto MetadataAddress = readMetadataFromInstance(ObjectAddress); if (!MetadataAddress) return nullptr; @@ -729,7 +733,7 @@ class ReflectionContext switch (*kind) { case MetadataKind::Class: - return getMetadataTypeInfo(*MetadataAddress); + return getMetadataTypeInfo(*MetadataAddress, ExternalTypeInfo); case MetadataKind::HeapLocalVariable: { auto CDAddr = this->readCaptureDescriptorFromMetadata(*MetadataAddress); @@ -751,7 +755,7 @@ class ReflectionContext auto Info = getBuilder().getClosureContextInfo(CD); - return getClosureContextInfo(ObjectAddress, Info); + return getClosureContextInfo(ObjectAddress, Info, ExternalTypeInfo); } case MetadataKind::HeapGenericLocalVariable: { @@ -760,7 +764,8 @@ class ReflectionContext if (auto Meta = readMetadata(*MetadataAddress)) { auto GenericHeapMeta = cast>(Meta.getLocalBuffer()); - return getMetadataTypeInfo(GenericHeapMeta->BoxedType); + return getMetadataTypeInfo(GenericHeapMeta->BoxedType, + ExternalTypeInfo); } return nullptr; } @@ -774,15 +779,15 @@ class ReflectionContext } } - bool - projectExistential(RemoteAddress ExistentialAddress, - const TypeRef *ExistentialTR, - const TypeRef **OutInstanceTR, - RemoteAddress *OutInstanceAddress) { + bool projectExistential(RemoteAddress ExistentialAddress, + const TypeRef *ExistentialTR, + const TypeRef **OutInstanceTR, + RemoteAddress *OutInstanceAddress, + remote::TypeInfoProvider *ExternalTypeInfo) { if (ExistentialTR == nullptr) return false; - auto ExistentialTI = getTypeInfo(ExistentialTR); + auto ExistentialTI = getTypeInfo(ExistentialTR, ExternalTypeInfo); if (ExistentialTI == nullptr) return false; @@ -846,14 +851,14 @@ class ReflectionContext /// Returns true if the enum case could be successfully determined. In /// particular, note that this code may return false for valid in-memory data /// if the compiler used a strategy we do not yet understand. - bool projectEnumValue(RemoteAddress EnumAddress, - const TypeRef *EnumTR, - int *CaseIndex) { + bool projectEnumValue(RemoteAddress EnumAddress, const TypeRef *EnumTR, + int *CaseIndex, + remote::TypeInfoProvider *ExternalTypeInfo) { // Get the TypeInfo and sanity-check it if (EnumTR == nullptr) { return false; } - auto TI = getTypeInfo(EnumTR); + auto TI = getTypeInfo(EnumTR, ExternalTypeInfo); if (TI == nullptr) { return false; } @@ -865,11 +870,12 @@ class ReflectionContext } /// Return a description of the layout of a value with the given type. - const TypeInfo *getTypeInfo(const TypeRef *TR) { + const TypeInfo *getTypeInfo(const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo) { if (TR == nullptr) { return nullptr; } else { - return getBuilder().getTypeConverter().getTypeInfo(TR); + return getBuilder().getTypeConverter().getTypeInfo(TR, ExternalTypeInfo); } } @@ -1160,8 +1166,9 @@ class ReflectionContext } private: - const TypeInfo *getClosureContextInfo(StoredPointer Context, - const ClosureContextInfo &Info) { + const TypeInfo * + getClosureContextInfo(StoredPointer Context, const ClosureContextInfo &Info, + remote::TypeInfoProvider *ExternalTypeInfo) { RecordTypeInfoBuilder Builder(getBuilder().getTypeConverter(), RecordKind::ClosureContext); @@ -1219,7 +1226,7 @@ class ReflectionContext SubstCaptureTR = OrigCaptureTR; if (SubstCaptureTR != nullptr) { - Builder.addField("", SubstCaptureTR); + Builder.addField("", SubstCaptureTR, ExternalTypeInfo); if (Builder.isInvalid()) return nullptr; diff --git a/include/swift/Reflection/TypeLowering.h b/include/swift/Reflection/TypeLowering.h index f3e59d14ac8b3..efee57fd9bce0 100644 --- a/include/swift/Reflection/TypeLowering.h +++ b/include/swift/Reflection/TypeLowering.h @@ -22,6 +22,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Casting.h" #include "swift/Remote/MetadataReader.h" +#include "swift/Remote/TypeInfoProvider.h" #include @@ -347,14 +348,16 @@ class TypeConverter { /// /// The type must either be concrete, or at least fixed-size, as /// determined by the isFixedSize() predicate. - const TypeInfo *getTypeInfo(const TypeRef *TR); + const TypeInfo *getTypeInfo(const TypeRef *TR, + remote::TypeInfoProvider *externalInfo); /// Returns layout information for an instance of the given /// class. /// /// Not cached. - const TypeInfo *getClassInstanceTypeInfo(const TypeRef *TR, - unsigned start); + const TypeInfo * + getClassInstanceTypeInfo(const TypeRef *TR, unsigned start, + remote::TypeInfoProvider *ExternalTypeInfo); private: friend class swift::reflection::LowerType; @@ -415,7 +418,8 @@ class RecordTypeInfoBuilder { bool bitwiseTakable); // Add a field of a record type, such as a struct. - void addField(const std::string &Name, const TypeRef *TR); + void addField(const std::string &Name, const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo); const RecordTypeInfo *build(); diff --git a/include/swift/Reflection/TypeRef.h b/include/swift/Reflection/TypeRef.h index 2637f616ae007..78bd159c5bdc2 100644 --- a/include/swift/Reflection/TypeRef.h +++ b/include/swift/Reflection/TypeRef.h @@ -156,8 +156,8 @@ class alignas(void *) TypeRef { bool isConcrete() const; bool isConcreteAfterSubstitutions(const GenericArgumentMap &Subs) const; - const TypeRef * - subst(TypeRefBuilder &Builder, const GenericArgumentMap &Subs) const; + const TypeRef *subst(TypeRefBuilder &Builder, + const GenericArgumentMap &Subs) const; llvm::Optional getSubstMap() const; diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index f375918a5ff5d..d2b7b48e65e15 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -634,16 +634,14 @@ class TypeRefBuilder { const std::string &Member, StringRef Protocol); - const TypeRef * - lookupSuperclass(const TypeRef *TR); + const TypeRef *lookupSuperclass(const TypeRef *TR); /// Load unsubstituted field types for a nominal type. - RemoteRef - getFieldTypeInfo(const TypeRef *TR); + RemoteRef getFieldTypeInfo(const TypeRef *TR); /// Get the parsed and substituted field types for a nominal type. - bool getFieldTypeRefs(const TypeRef *TR, - RemoteRef FD, + bool getFieldTypeRefs(const TypeRef *TR, RemoteRef FD, + remote::TypeInfoProvider *ExternalTypeInfo, std::vector &Fields); /// Get the primitive type lowering for a builtin type. diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index 6575f83f3cf25..6dfd4c755a487 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -37,7 +37,8 @@ namespace remote { class MemoryReader { public: /// A convenient name for the return type from readBytes. - using ReadBytesResult = std::unique_ptr>; + using ReadBytesResult = + std::unique_ptr>; virtual bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, void *outBuffer) = 0; @@ -152,9 +153,8 @@ class MemoryReader { return resolvePointer(address, pointerData); } - - // Parse extra inhabitants stored in a pointer. + // Parse extra inhabitants stored in a pointer. // Sets *extraInhabitant to -1 if the pointer at this address // is actually a valid pointer. // Otherwise, it sets *extraInhabitant to the inhabitant diff --git a/include/swift/Remote/TypeInfoProvider.h b/include/swift/Remote/TypeInfoProvider.h new file mode 100644 index 0000000000000..73995ca069247 --- /dev/null +++ b/include/swift/Remote/TypeInfoProvider.h @@ -0,0 +1,39 @@ +//===--- TypeInfoProvider.h - Abstract access to type info ------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file declares an abstract interface for reading type layout info. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_REMOTE_TYPEINFOPROVIDER_H +#define SWIFT_REMOTE_TYPEINFOPROVIDER_H + +namespace swift { +namespace reflection { +class TypeInfo; +} +namespace remote { + +/// An abstract interface for providing external type layout information. +struct TypeInfoProvider { + virtual ~TypeInfoProvider() = default; + + /// Attempt to read type information about (Clang)imported types that are not + /// represented in the metadata. LLDB can read this information from debug + /// info, for example. + virtual const reflection::TypeInfo * + getTypeInfo(llvm::StringRef mangledName) = 0; +}; + +} // namespace remote +} // namespace swift +#endif diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index 0c15c3da24e3e..bd95c5f00e6da 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -1034,7 +1034,10 @@ class ExistentialTypeInfoBuilder { ++WitnessTableCount; if (auto *Superclass = TC.getBuilder().lookupSuperclass(P)) { - auto *SuperclassTI = TC.getTypeInfo(Superclass); + // ObjC class info should be available in the metadata, so it's safe + // to not pass an external provider here. This helps preserving the + // layering. + auto *SuperclassTI = TC.getTypeInfo(Superclass, nullptr); if (SuperclassTI == nullptr) { DEBUG_LOG(fprintf(stderr, "No TypeInfo for superclass: "); Superclass->dump()); @@ -1140,7 +1143,7 @@ class ExistentialTypeInfoBuilder { Invalid = true; } - const TypeInfo *build() { + const TypeInfo *build(remote::TypeInfoProvider *ExternalTypeInfo) { examineProtocols(); if (Invalid) @@ -1176,12 +1179,14 @@ class ExistentialTypeInfoBuilder { // Class existentials consist of a single retainable pointer // followed by witness tables. if (Refcounting == ReferenceCounting::Unknown) - builder.addField("object", TC.getUnknownObjectTypeRef()); + builder.addField("object", TC.getUnknownObjectTypeRef(), + ExternalTypeInfo); else - builder.addField("object", TC.getNativeObjectTypeRef()); + builder.addField("object", TC.getNativeObjectTypeRef(), + ExternalTypeInfo); break; case ExistentialTypeRepresentation::Opaque: { - auto *TI = TC.getTypeInfo(TC.getRawPointerTypeRef()); + auto *TI = TC.getTypeInfo(TC.getRawPointerTypeRef(), ExternalTypeInfo); if (TI == nullptr) { DEBUG_LOG(fprintf(stderr, "No TypeInfo for RawPointer\n")); return nullptr; @@ -1195,21 +1200,21 @@ class ExistentialTypeInfoBuilder { TI->getAlignment(), /*numExtraInhabitants=*/0, /*bitwiseTakable=*/true); - builder.addField("metadata", TC.getAnyMetatypeTypeRef()); + builder.addField("metadata", TC.getAnyMetatypeTypeRef(), ExternalTypeInfo); break; } case ExistentialTypeRepresentation::Error: - builder.addField("error", TC.getUnknownObjectTypeRef()); + builder.addField("error", TC.getUnknownObjectTypeRef(), ExternalTypeInfo); break; } for (unsigned i = 0; i < WitnessTableCount; ++i) - builder.addField("wtable", TC.getRawPointerTypeRef()); + builder.addField("wtable", TC.getRawPointerTypeRef(), ExternalTypeInfo); return builder.build(); } - const TypeInfo *buildMetatype() { + const TypeInfo *buildMetatype(remote::TypeInfoProvider *ExternalTypeInfo) { examineProtocols(); if (Invalid) @@ -1226,9 +1231,9 @@ class ExistentialTypeInfoBuilder { RecordTypeInfoBuilder builder(TC, RecordKind::ExistentialMetatype); - builder.addField("metadata", TC.getAnyMetatypeTypeRef()); + builder.addField("metadata", TC.getAnyMetatypeTypeRef(), ExternalTypeInfo); for (unsigned i = 0; i < WitnessTableCount; ++i) - builder.addField("wtable", TC.getRawPointerTypeRef()); + builder.addField("wtable", TC.getRawPointerTypeRef(), ExternalTypeInfo); return builder.build(); } @@ -1285,9 +1290,10 @@ unsigned RecordTypeInfoBuilder::addField(unsigned fieldSize, return offset; } -void RecordTypeInfoBuilder::addField(const std::string &Name, - const TypeRef *TR) { - const TypeInfo *TI = TC.getTypeInfo(TR); +void RecordTypeInfoBuilder::addField( + const std::string &Name, const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo) { + const TypeInfo *TI = TC.getTypeInfo(TR, ExternalTypeInfo); if (TI == nullptr) { DEBUG_LOG(fprintf(stderr, "No TypeInfo for field type: "); TR->dump()); Invalid = true; @@ -1394,14 +1400,13 @@ TypeConverter::getThinFunctionTypeInfo() { /// Thick functions consist of a function pointer and nullable retainable /// context pointer. The context is modeled exactly like a native Swift /// class reference. -const TypeInfo * -TypeConverter::getThickFunctionTypeInfo() { +const TypeInfo *TypeConverter::getThickFunctionTypeInfo() { if (ThickFunctionTI != nullptr) return ThickFunctionTI; RecordTypeInfoBuilder builder(*this, RecordKind::ThickFunction); - builder.addField("function", getThinFunctionTypeRef()); - builder.addField("context", getNativeObjectTypeRef()); + builder.addField("function", getThinFunctionTypeRef(), nullptr); + builder.addField("context", getNativeObjectTypeRef(), nullptr); ThickFunctionTI = builder.build(); return ThickFunctionTI; @@ -1758,14 +1763,14 @@ class EnumTypeInfoBuilder { : TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0), BitwiseTakable(true), Invalid(false) {} - const TypeInfo * - build(const TypeRef *TR, RemoteRef FD) { + const TypeInfo *build(const TypeRef *TR, RemoteRef FD, + remote::TypeInfoProvider *ExternalTypeInfo) { // Sort enum into payload and no-payload cases. unsigned NoPayloadCases = 0; std::vector PayloadCases; std::vector Fields; - if (!TC.getBuilder().getFieldTypeRefs(TR, FD, Fields)) { + if (!TC.getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields)) { Invalid = true; return nullptr; } @@ -1777,7 +1782,7 @@ class EnumTypeInfoBuilder { } else { PayloadCases.push_back(Case); auto *CaseTR = getCaseTypeRef(Case); - auto *CaseTI = TC.getTypeInfo(CaseTR); + auto *CaseTI = TC.getTypeInfo(CaseTR, ExternalTypeInfo); addCase(Case.Name, CaseTR, CaseTI); } } @@ -1810,7 +1815,7 @@ class EnumTypeInfoBuilder { } else if (PayloadCases.size() == 1) { // SinglePayloadEnumImplStrategy auto *CaseTR = getCaseTypeRef(PayloadCases[0]); - auto *CaseTI = TC.getTypeInfo(CaseTR); + auto *CaseTI = TC.getTypeInfo(CaseTR, ExternalTypeInfo); if (CaseTR == nullptr || CaseTI == nullptr) { return nullptr; } @@ -1910,11 +1915,13 @@ class EnumTypeInfoBuilder { class LowerType : public TypeRefVisitor { TypeConverter &TC; + remote::TypeInfoProvider *ExternalTypeInfo; public: using TypeRefVisitor::visit; - LowerType(TypeConverter &TC) : TC(TC) {} + LowerType(TypeConverter &TC, remote::TypeInfoProvider *ExternalTypeInfo) + : TC(TC), ExternalTypeInfo(ExternalTypeInfo) {} const TypeInfo *visitBuiltinTypeRef(const BuiltinTypeRef *B) { /// The context field of a thick function is a Builtin.NativeObject. @@ -1950,6 +1957,18 @@ class LowerType // Otherwise, we're out of luck. if (FD == nullptr) { + if (ExternalTypeInfo) { + // Ask the ExternalTypeInfo. It may be a Clang-imported type. + std::string MangledName; + if (auto N = dyn_cast(TR)) + MangledName = N->getMangledName(); + else if (auto BG = dyn_cast(TR)) + MangledName = BG->getMangledName(); + if (!MangledName.empty()) + if (auto *imported = ExternalTypeInfo->getTypeInfo(MangledName)) + return imported; + } + DEBUG_LOG(fprintf(stderr, "No TypeInfo for nominal type: "); TR->dump()); return nullptr; } @@ -1966,17 +1985,17 @@ class LowerType RecordTypeInfoBuilder builder(TC, RecordKind::Struct); std::vector Fields; - if (!TC.getBuilder().getFieldTypeRefs(TR, FD, Fields)) + if (!TC.getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields)) return nullptr; for (auto Field : Fields) - builder.addField(Field.Name, Field.TR); + builder.addField(Field.Name, Field.TR, ExternalTypeInfo); return builder.build(); } case FieldDescriptorKind::Enum: case FieldDescriptorKind::MultiPayloadEnum: { EnumTypeInfoBuilder builder(TC); - return builder.build(TR, FD); + return builder.build(TR, FD, ExternalTypeInfo); } case FieldDescriptorKind::ObjCClass: return TC.getReferenceTypeInfo(ReferenceKind::Strong, @@ -2002,7 +2021,7 @@ class LowerType const TypeInfo *visitTupleTypeRef(const TupleTypeRef *T) { RecordTypeInfoBuilder builder(TC, RecordKind::Tuple); for (auto Element : T->getElements()) - builder.addField("", Element); + builder.addField("", Element, ExternalTypeInfo); return builder.build(); } @@ -2016,7 +2035,7 @@ class LowerType ReferenceCounting::Unknown); case FunctionMetadataConvention::Thin: case FunctionMetadataConvention::CFunctionPointer: - return TC.getTypeInfo(TC.getThinFunctionTypeRef()); + return TC.getTypeInfo(TC.getThinFunctionTypeRef(), ExternalTypeInfo); } swift_runtime_unreachable("Unhandled FunctionMetadataConvention in switch."); @@ -2026,7 +2045,7 @@ class LowerType visitProtocolCompositionTypeRef(const ProtocolCompositionTypeRef *PC) { ExistentialTypeInfoBuilder builder(TC); builder.addProtocolComposition(PC); - return builder.build(); + return builder.build(ExternalTypeInfo); } const TypeInfo *visitMetatypeTypeRef(const MetatypeTypeRef *M) { @@ -2037,7 +2056,7 @@ class LowerType case MetatypeRepresentation::Thin: return TC.getEmptyTypeInfo(); case MetatypeRepresentation::Thick: - return TC.getTypeInfo(TC.getAnyMetatypeTypeRef()); + return TC.getTypeInfo(TC.getAnyMetatypeTypeRef(), ExternalTypeInfo); } swift_runtime_unreachable("Unhandled MetatypeRepresentation in switch."); @@ -2055,7 +2074,7 @@ class LowerType return nullptr; } - return builder.buildMetatype(); + return builder.buildMetatype(ExternalTypeInfo); } const TypeInfo * @@ -2102,7 +2121,7 @@ class LowerType if (auto *EnumTI = dyn_cast(TI)) { if (EnumTI->isOptional() && Kind == ReferenceKind::Weak) { - auto *TI = TC.getTypeInfo(EnumTI->getCases()[0].TR); + auto *TI = TC.getTypeInfo(EnumTI->getCases()[0].TR, ExternalTypeInfo); return rebuildStorageTypeInfo(TI, Kind); } } @@ -2142,7 +2161,7 @@ class LowerType const TypeInfo * visitAnyStorageTypeRef(const TypeRef *TR, ReferenceKind Kind) { - return rebuildStorageTypeInfo(TC.getTypeInfo(TR), Kind); + return rebuildStorageTypeInfo(TC.getTypeInfo(TR, ExternalTypeInfo), Kind); } #define REF_STORAGE(Name, name, ...) \ @@ -2170,7 +2189,9 @@ class LowerType } }; -const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) { +const TypeInfo * +TypeConverter::getTypeInfo(const TypeRef *TR, + remote::TypeInfoProvider *ExternalTypeInfo) { // See if we already computed the result auto found = Cache.find(TR); if (found != Cache.end()) @@ -2184,7 +2205,7 @@ const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) { } // Compute the result and cache it - auto *TI = LowerType(*this).visit(TR); + auto *TI = LowerType(*this, ExternalTypeInfo).visit(TR); Cache[TR] = TI; RecursionCheck.erase(TR); @@ -2192,8 +2213,9 @@ const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) { return TI; } -const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, - unsigned start) { +const TypeInfo *TypeConverter::getClassInstanceTypeInfo( + const TypeRef *TR, unsigned start, + remote::TypeInfoProvider *ExternalTypeInfo) { auto FD = getBuilder().getFieldTypeInfo(TR); if (FD == nullptr) { DEBUG_LOG(fprintf(stderr, "No field descriptor: "); TR->dump()); @@ -2208,7 +2230,7 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, RecordTypeInfoBuilder builder(*this, RecordKind::ClassInstance); std::vector Fields; - if (!getBuilder().getFieldTypeRefs(TR, FD, Fields)) + if (!getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields)) return nullptr; // Start layout from the given instance start offset. This should @@ -2219,7 +2241,7 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR, /*bitwiseTakable=*/true); for (auto Field : Fields) - builder.addField(Field.Name, Field.TR); + builder.addField(Field.Name, Field.TR, ExternalTypeInfo); return builder.build(); } case FieldDescriptorKind::Struct: diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp index d1ef7a63351e7..ee90fde27b3c1 100644 --- a/stdlib/public/Reflection/TypeRef.cpp +++ b/stdlib/public/Reflection/TypeRef.cpp @@ -901,7 +901,7 @@ class TypeRefSubstitution using TypeRefVisitor::visit; TypeRefSubstitution(TypeRefBuilder &Builder, GenericArgumentMap Substitutions) - : Builder(Builder), Substitutions(Substitutions) {} + : Builder(Builder), Substitutions(Substitutions) {} const TypeRef *visitBuiltinTypeRef(const BuiltinTypeRef *B) { return B; @@ -1081,8 +1081,8 @@ class TypeRefSubstitution } }; -const TypeRef * -TypeRef::subst(TypeRefBuilder &Builder, const GenericArgumentMap &Subs) const { +const TypeRef *TypeRef::subst(TypeRefBuilder &Builder, + const GenericArgumentMap &Subs) const { return TypeRefSubstitution(Builder, Subs).visit(this); } diff --git a/stdlib/public/Reflection/TypeRefBuilder.cpp b/stdlib/public/Reflection/TypeRefBuilder.cpp index 772afeb1e98f2..dfed07ec96147 100644 --- a/stdlib/public/Reflection/TypeRefBuilder.cpp +++ b/stdlib/public/Reflection/TypeRefBuilder.cpp @@ -145,8 +145,7 @@ lookupTypeWitness(const std::string &MangledTypeName, return nullptr; } -const TypeRef * TypeRefBuilder:: -lookupSuperclass(const TypeRef *TR) { +const TypeRef *TypeRefBuilder::lookupSuperclass(const TypeRef *TR) { const auto &FD = getFieldTypeInfo(TR); if (FD == nullptr) return nullptr; @@ -202,8 +201,8 @@ TypeRefBuilder::getFieldTypeInfo(const TypeRef *TR) { } bool TypeRefBuilder::getFieldTypeRefs( - const TypeRef *TR, - RemoteRef FD, + const TypeRef *TR, RemoteRef FD, + remote::TypeInfoProvider *ExternalTypeInfo, std::vector &Fields) { if (FD == nullptr) return false; diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 114cf058512d0..a1e6576b66e9d 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -471,7 +471,7 @@ swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); - auto TI = Context->getTypeInfo(TR); + auto TI = Context->getTypeInfo(TR, nullptr); return convertTypeInfo(TI); } @@ -481,7 +481,7 @@ swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef, unsigned Index) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); - auto *TI = Context->getTypeInfo(TR); + auto *TI = Context->getTypeInfo(TR, nullptr); return convertChild(TI, Index); } @@ -489,7 +489,7 @@ swift_typeinfo_t swift_reflection_infoForMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getMetadataTypeInfo(Metadata); + auto *TI = Context->getMetadataTypeInfo(Metadata, nullptr); return convertTypeInfo(TI); } @@ -498,7 +498,7 @@ swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata, unsigned Index) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getMetadataTypeInfo(Metadata); + auto *TI = Context->getMetadataTypeInfo(Metadata, nullptr); return convertChild(TI, Index); } @@ -506,7 +506,7 @@ swift_typeinfo_t swift_reflection_infoForInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getInstanceTypeInfo(Object); + auto *TI = Context->getInstanceTypeInfo(Object, nullptr); return convertTypeInfo(TI); } @@ -515,7 +515,7 @@ swift_reflection_childOfInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object, unsigned Index) { auto Context = ContextRef->nativeContext; - auto *TI = Context->getInstanceTypeInfo(Object); + auto *TI = Context->getInstanceTypeInfo(Object, nullptr); return convertChild(TI, Index); } @@ -529,10 +529,9 @@ int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef, auto RemoteExistentialAddress = RemoteAddress(ExistentialAddress); const TypeRef *InstanceTR = nullptr; RemoteAddress RemoteStartOfInstanceData(nullptr); - auto Success = Context->projectExistential(RemoteExistentialAddress, - ExistentialTR, - &InstanceTR, - &RemoteStartOfInstanceData); + auto Success = Context->projectExistential( + RemoteExistentialAddress, ExistentialTR, &InstanceTR, + &RemoteStartOfInstanceData, nullptr); if (Success) { *InstanceTypeRef = reinterpret_cast(InstanceTR); @@ -549,10 +548,11 @@ int swift_reflection_projectEnumValue(SwiftReflectionContextRef ContextRef, auto Context = ContextRef->nativeContext; auto EnumTR = reinterpret_cast(EnumTypeRef); auto RemoteEnumAddress = RemoteAddress(EnumAddress); - if (!Context->projectEnumValue(RemoteEnumAddress, EnumTR, CaseIndex)) { + if (!Context->projectEnumValue(RemoteEnumAddress, EnumTR, CaseIndex, + nullptr)) { return false; } - auto TI = Context->getTypeInfo(EnumTR); + auto TI = Context->getTypeInfo(EnumTR, nullptr); auto *RecordTI = dyn_cast(TI); assert(RecordTI != nullptr); if (static_cast(*CaseIndex) >= RecordTI->getNumCases()) { @@ -574,7 +574,7 @@ void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); - auto TI = Context->getTypeInfo(TR); + auto TI = Context->getTypeInfo(TR, nullptr); if (TI == nullptr) { fprintf(stdout, "\n"); } else { @@ -599,7 +599,7 @@ void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef, void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata) { auto Context = ContextRef->nativeContext; - auto TI = Context->getMetadataTypeInfo(Metadata); + auto TI = Context->getMetadataTypeInfo(Metadata, nullptr); if (TI == nullptr) { fprintf(stdout, "\n"); } else { @@ -610,7 +610,7 @@ void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef, void swift_reflection_dumpInfoForInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; - auto TI = Context->getInstanceTypeInfo(Object); + auto TI = Context->getInstanceTypeInfo(Object, nullptr); if (TI == nullptr) { fprintf(stdout, "%s", "\n"); } else { diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp index c06ec35de5f81..53a2a680085f8 100644 --- a/tools/swift-reflection-dump/swift-reflection-dump.cpp +++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp @@ -583,25 +583,28 @@ class ObjectMemoryReader : public MemoryReader { using ReflectionContextOwner = std::unique_ptr; -template -static std::pair -makeReflectionContextForMetadataReader( - std::shared_ptr reader) { +struct ReflectionContextHolder { + ReflectionContextOwner Owner; + TypeRefBuilder &Builder; + ObjectMemoryReader &Reader; +}; + +template +static ReflectionContextHolder makeReflectionContextForMetadataReader( + std::shared_ptr reader) { using ReflectionContext = ReflectionContext; auto context = new ReflectionContext(reader); auto &builder = context->getBuilder(); for (unsigned i = 0, e = reader->getImages().size(); i < e; ++i) { context->addImage(reader->getImageStartAddress(i)); } - return {ReflectionContextOwner(context, - [](void *x){ delete (ReflectionContext*)x; }), - builder}; + return {ReflectionContextOwner( + context, [](void *x) { delete (ReflectionContext *)x; }), + builder, *reader}; } - -static std::pair -makeReflectionContextForObjectFiles( - const std::vector &objectFiles) { +static ReflectionContextHolder makeReflectionContextForObjectFiles( + const std::vector &objectFiles) { auto Reader = std::make_shared(objectFiles); uint8_t pointerSize; @@ -651,7 +654,7 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, } auto context = makeReflectionContextForObjectFiles(ObjectFiles); - auto &builder = context.second; + auto &builder = context.Builder; switch (Action) { case ActionType::DumpReflectionSections: @@ -676,7 +679,7 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, } TypeRef->dump(file); - auto *TypeInfo = builder.getTypeConverter().getTypeInfo(TypeRef); + auto *TypeInfo = builder.getTypeConverter().getTypeInfo(TypeRef, nullptr); if (TypeInfo == nullptr) { fprintf(file, "Invalid lowering\n"); continue; From 961dc59cf5ff026ab3de174a44c915daf7dc9941 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 14 Aug 2020 11:54:25 -0700 Subject: [PATCH 328/663] Thread Labels through TupleTypeRef. --- include/swift/Reflection/TypeRef.h | 39 +++++++++++++++++------ include/swift/Reflection/TypeRefBuilder.h | 4 +-- stdlib/public/Reflection/TypeLowering.cpp | 1 + stdlib/public/Reflection/TypeRef.cpp | 26 +++++++++++---- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/include/swift/Reflection/TypeRef.h b/include/swift/Reflection/TypeRef.h index 78bd159c5bdc2..fb03cbc9e2e82 100644 --- a/include/swift/Reflection/TypeRef.h +++ b/include/swift/Reflection/TypeRef.h @@ -301,27 +301,48 @@ class BoundGenericTypeRef final : public TypeRef, public NominalTypeTrait { }; class TupleTypeRef final : public TypeRef { +protected: std::vector Elements; + std::string Labels; - static TypeRefID Profile(const std::vector &Elements) { + static TypeRefID Profile(const std::vector &Elements, + const std::string &Labels) { TypeRefID ID; for (auto Element : Elements) ID.addPointer(Element); + ID.addString(Labels); return ID; } public: - TupleTypeRef(std::vector Elements) - : TypeRef(TypeRefKind::Tuple), Elements(std::move(Elements)) {} + TupleTypeRef(std::vector Elements, std::string &&Labels) + : TypeRef(TypeRefKind::Tuple), Elements(std::move(Elements)), + Labels(Labels) {} template static const TupleTypeRef *create(Allocator &A, - std::vector Elements) { - FIND_OR_CREATE_TYPEREF(A, TupleTypeRef, Elements); - } - - const std::vector &getElements() const { - return Elements; + std::vector Elements, + std::string &&Labels) { + FIND_OR_CREATE_TYPEREF(A, TupleTypeRef, Elements, Labels); + } + + const std::vector &getElements() const { return Elements; }; + const std::string &getLabelString() const { return Labels; }; + std::vector getLabels() const { + std::vector Vec; + std::string::size_type End, Start = 0; + while (true) { + End = Labels.find(' ', Start); + if (End == std::string::npos) + break; + Vec.push_back(llvm::StringRef(Labels.data() + Start, End - Start)); + Start = End + 1; + } + // A canonicalized TypeRef has an empty label string. + // Pad the vector with empty labels. + for (unsigned N = Vec.size(); N < Elements.size(); ++N) + Vec.push_back({}); + return Vec; }; static bool classof(const TypeRef *TR) { diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index d2b7b48e65e15..1423a55e395c8 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -405,9 +405,7 @@ class TypeRefBuilder { const TupleTypeRef *createTupleType(llvm::ArrayRef elements, std::string &&labels) { - // FIXME: Add uniqueness checks in TupleTypeRef::Profile and - // unittests/Reflection/TypeRef.cpp if using labels for identity. - return TupleTypeRef::create(*this, elements); + return TupleTypeRef::create(*this, elements, std::move(labels)); } const FunctionTypeRef *createFunctionType( diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index bd95c5f00e6da..b22add689d9dd 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -2021,6 +2021,7 @@ class LowerType const TypeInfo *visitTupleTypeRef(const TupleTypeRef *T) { RecordTypeInfoBuilder builder(TC, RecordKind::Tuple); for (auto Element : T->getElements()) + // The label is not going to be relevant/harmful for looking up type info. builder.addField("", Element, ExternalTypeInfo); return builder.build(); } diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp index ee90fde27b3c1..ba63a72ea8384 100644 --- a/stdlib/public/Reflection/TypeRef.cpp +++ b/stdlib/public/Reflection/TypeRef.cpp @@ -109,8 +109,14 @@ class PrintTypeRef : public TypeRefVisitor { void visitTupleTypeRef(const TupleTypeRef *T) { printHeader("tuple"); - for (auto element : T->getElements()) - printRec(element); + T->getLabels(); + auto Labels = T->getLabels(); + for (auto NameElement : llvm::zip_first(Labels, T->getElements())) { + auto Label = std::get<0>(NameElement); + if (!Label.empty()) + fprintf(file, "%s = ", Label.str().c_str()); + printRec(std::get<1>(NameElement)); + } fprintf(file, ")"); } @@ -459,9 +465,15 @@ class DemanglingForTypeRef Demangle::NodePointer visitTupleTypeRef(const TupleTypeRef *T) { auto tuple = Dem.createNode(Node::Kind::Tuple); - for (auto element : T->getElements()) { + auto Labels = T->getLabels(); + for (auto LabelElement : llvm::zip(Labels, T->getElements())) { auto tupleElt = Dem.createNode(Node::Kind::TupleElement); - tupleElt->addChild(visit(element), Dem); + auto Label = std::get<0>(LabelElement); + if (!Label.empty()) { + auto name = Dem.createNode(Node::Kind::TupleElementName, Label); + tupleElt->addChild(name, Dem); + } + tupleElt->addChild(visit(std::get<1>(LabelElement)), Dem); tuple->addChild(tupleElt, Dem); } return tuple; @@ -816,7 +828,8 @@ class ThickenMetatype std::vector Elements; for (auto Element : T->getElements()) Elements.push_back(visit(Element)); - return TupleTypeRef::create(Builder, Elements); + std::string Labels = T->getLabelString(); + return TupleTypeRef::create(Builder, Elements, std::move(Labels)); } const TypeRef *visitFunctionTypeRef(const FunctionTypeRef *F) { @@ -929,7 +942,8 @@ class TypeRefSubstitution std::vector Elements; for (auto Element : T->getElements()) Elements.push_back(visit(Element)); - return TupleTypeRef::create(Builder, Elements); + std::string Labels = T->getLabelString(); + return TupleTypeRef::create(Builder, Elements, std::move(Labels)); } const TypeRef *visitFunctionTypeRef(const FunctionTypeRef *F) { From 9287707520b1266b23bc625a18e6075204f81e90 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 20 Aug 2020 15:03:27 -0700 Subject: [PATCH 329/663] Support generic parent contexts in DemanglingForTypeRef. --- stdlib/public/Reflection/TypeRef.cpp | 37 ++++++++++++++++--- validation-test/Reflection/existentials.swift | 2 +- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp index ba63a72ea8384..83e9e36b3a5e0 100644 --- a/stdlib/public/Reflection/TypeRef.cpp +++ b/stdlib/public/Reflection/TypeRef.cpp @@ -406,6 +406,14 @@ class DemanglingForTypeRef : public TypeRefVisitor { Demangle::Demangler &Dem; + /// Demangle a type and dive into the outermost Type node. + Demangle::NodePointer demangleAndUnwrapType(llvm::StringRef mangledName) { + auto node = Dem.demangleType(mangledName); + if (node && node->getKind() == Node::Kind::Type && node->getNumChildren()) + node = node->getFirstChild(); + return node; + } + public: DemanglingForTypeRef(Demangle::Demangler &Dem) : Dem(Dem) {} @@ -420,13 +428,32 @@ class DemanglingForTypeRef } Demangle::NodePointer visitBuiltinTypeRef(const BuiltinTypeRef *B) { - return Dem.demangleType(B->getMangledName()); + return demangleAndUnwrapType(B->getMangledName()); } Demangle::NodePointer visitNominalTypeRef(const NominalTypeRef *N) { - if (auto parent = N->getParent()) - assert(false && "not implemented"); - return Dem.demangleType(N->getMangledName()); + auto node = demangleAndUnwrapType(N->getMangledName()); + if (!node || node->getNumChildren() != 2) + return node; + + auto parent = N->getParent(); + if (!parent) + return node; + + // Swap in the richer parent that is stored in the NominalTypeRef + // instead of what is encoded in the mangled name. The mangled name's + // context has been "unspecialized" by NodeBuilder. + auto parentNode = visit(parent); + if (!parentNode) + return node; + if (parentNode->getKind() == Node::Kind::Type && + parentNode->getNumChildren()) + parentNode = parentNode->getFirstChild(); + + auto contextualizedNode = Dem.createNode(node->getKind()); + contextualizedNode->addChild(parentNode, Dem); + contextualizedNode->addChild(node->getChild(1), Dem); + return contextualizedNode; } Demangle::NodePointer @@ -650,7 +677,7 @@ class DemanglingForTypeRef } Demangle::NodePointer visitForeignClassTypeRef(const ForeignClassTypeRef *F) { - return Dem.demangleType(F->getName()); + return demangleAndUnwrapType(F->getName()); } Demangle::NodePointer visitObjCClassTypeRef(const ObjCClassTypeRef *OC) { diff --git a/validation-test/Reflection/existentials.swift b/validation-test/Reflection/existentials.swift index ce17f8f4916d2..6377102c7ce63 100644 --- a/validation-test/Reflection/existentials.swift +++ b/validation-test/Reflection/existentials.swift @@ -281,7 +281,7 @@ protocol Composition : P, Q {} struct S : Composition {} func getComposition() -> P & Q { return S() } reflect(any: getComposition()) -// CHECK-64: Mangled name: $s12existentials1PP_AA1QPp +// CHECK-64: Mangled name: $s12existentials1P_AA1Qp // CHECK-64: Demangled name: existentials.P & existentials.Q // CHECK-32: Mangled name: $s12existentials1PP_AA1QPp // CHECK-32: Demangled name: existentials.P & existentials.Q From 7815ecf2a0137e82292b195d4dc92db346afc9d8 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Mon, 24 Aug 2020 23:44:11 -0300 Subject: [PATCH 330/663] [CSApply] Handle OptionalForce component when is initial component on key path expr --- lib/Sema/CSApply.cpp | 16 ++++++++++++++-- test/Constraints/keypath.swift | 8 ++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 276974ed4ab42..0add614158d91 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -4732,9 +4732,21 @@ namespace { KeyPathExpr::Component::forOptionalChain(objectTy, loc)); break; } - case KeyPathExpr::Component::Kind::OptionalForce: - buildKeyPathOptionalForceComponent(resolvedComponents); + case KeyPathExpr::Component::Kind::OptionalForce: { + // Handle force optional when it is the first component e.g. + // \String?.!.count + if (resolvedComponents.empty()) { + auto loc = origComponent.getLoc(); + auto objectTy = componentTy->getOptionalObjectType(); + assert(objectTy); + + resolvedComponents.push_back( + KeyPathExpr::Component::forOptionalForce(objectTy, loc)); + } else { + buildKeyPathOptionalForceComponent(resolvedComponents); + } break; + } case KeyPathExpr::Component::Kind::Invalid: { auto component = origComponent; component.setComponentType(leafTy); diff --git a/test/Constraints/keypath.swift b/test/Constraints/keypath.swift index 107739ee0b9a8..2512e9d9f372b 100644 --- a/test/Constraints/keypath.swift +++ b/test/Constraints/keypath.swift @@ -179,3 +179,11 @@ func key_path_root_mismatch(_ base: KeyPathBase?, subBase: KeyPathBaseSubtype let _ : T = subBase[keyPath: kpa] // expected-error {{key path with root type 'AnotherBase' cannot be applied to a base of type 'KeyPathBaseSubtype?'}} } + +// SR-13442 +func SR13442(_ x: KeyPath) -> T { "1"[keyPath: x] } + +func testSR13442() { + _ = SR13442(\.!.count) // OK + _ = SR13442(\String?.!.count) // OK +} From 9b5b265306a90cf1f3809c729b3ce803318d77f9 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 21 Aug 2020 17:55:19 -0700 Subject: [PATCH 331/663] Take TypeInfoProvider into account when caching TypeInfos. --- include/swift/Reflection/TypeLowering.h | 3 ++- lib/AST/ASTDemangler.cpp | 2 +- stdlib/public/Reflection/TypeLowering.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/swift/Reflection/TypeLowering.h b/include/swift/Reflection/TypeLowering.h index efee57fd9bce0..9c278fa7ac3ac 100644 --- a/include/swift/Reflection/TypeLowering.h +++ b/include/swift/Reflection/TypeLowering.h @@ -317,7 +317,8 @@ class ReferenceTypeInfo : public TypeInfo { class TypeConverter { TypeRefBuilder &Builder; std::vector> Pool; - llvm::DenseMap Cache; + llvm::DenseMap, + const TypeInfo *> Cache; llvm::DenseSet RecursionCheck; llvm::DenseMap, const ReferenceTypeInfo *> ReferenceCache; diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 6e44fd70da0ef..3600be0b03b9d 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -144,7 +144,7 @@ Type ASTBuilder::createNominalType(GenericTypeDecl *decl, Type parent) { return Type(); // If the declaration is generic, fail. - if (nominalDecl->getGenericParams()) + if (auto list = nominalDecl->getGenericParams()) return Type(); // Imported types can be renamed to be members of other (non-generic) diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index b22add689d9dd..729765edd1893 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -2194,7 +2194,7 @@ const TypeInfo * TypeConverter::getTypeInfo(const TypeRef *TR, remote::TypeInfoProvider *ExternalTypeInfo) { // See if we already computed the result - auto found = Cache.find(TR); + auto found = Cache.find({TR, ExternalTypeInfo}); if (found != Cache.end()) return found->second; @@ -2207,7 +2207,7 @@ TypeConverter::getTypeInfo(const TypeRef *TR, // Compute the result and cache it auto *TI = LowerType(*this, ExternalTypeInfo).visit(TR); - Cache[TR] = TI; + Cache.insert({{TR, ExternalTypeInfo}, TI}); RecursionCheck.erase(TR); From 56b2e906da8c844b5746bbfd752f3504fd936290 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 25 Aug 2020 15:44:28 -0700 Subject: [PATCH 332/663] Support MetatypeTypeRefs in DemanglingForTypeRef. --- stdlib/public/Reflection/TypeRef.cpp | 5 ++++- validation-test/Reflection/existentials.swift | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp index 83e9e36b3a5e0..5b5b1ddebb630 100644 --- a/stdlib/public/Reflection/TypeRef.cpp +++ b/stdlib/public/Reflection/TypeRef.cpp @@ -644,7 +644,10 @@ class DemanglingForTypeRef Demangle::NodePointer visitMetatypeTypeRef(const MetatypeTypeRef *M) { auto node = Dem.createNode(Node::Kind::Metatype); - assert(!M->wasAbstract() && "not implemented"); + // FIXME: This is lossy. @objc_metatype is also abstract. + auto repr = Dem.createNode(Node::Kind::MetatypeRepresentation, + M->wasAbstract() ? "@thick" : "@thin"); + node->addChild(repr, Dem); node->addChild(visit(M->getInstanceType()), Dem); return node; } diff --git a/validation-test/Reflection/existentials.swift b/validation-test/Reflection/existentials.swift index 6377102c7ce63..ea8b44587b350 100644 --- a/validation-test/Reflection/existentials.swift +++ b/validation-test/Reflection/existentials.swift @@ -283,15 +283,15 @@ func getComposition() -> P & Q { return S() } reflect(any: getComposition()) // CHECK-64: Mangled name: $s12existentials1P_AA1Qp // CHECK-64: Demangled name: existentials.P & existentials.Q -// CHECK-32: Mangled name: $s12existentials1PP_AA1QPp +// CHECK-32: Mangled name: $s12existentials1P_AA1Qp // CHECK-32: Demangled name: existentials.P & existentials.Q // Metatype: reflect(any: Int.self) -// CHECK-64: Mangled name: $sSim -// CHECK-64: Demangled name: Swift.Int.Type -// CHECK-32: Mangled name: $sSim -// CHECK-32: Demangled name: Swift.Int.Type +// CHECK-64: Mangled name: $sSiXMt +// CHECK-64: Demangled name: @thin Swift.Int.Type +// CHECK-32: Mangled name: $sSiXMt +// CHECK-32: Demangled name: @thin Swift.Int.Type protocol WithType { associatedtype T From 8f72547e2fee46358a232981f62bceecd2d38504 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 25 Aug 2020 16:37:48 -0700 Subject: [PATCH 333/663] [test] ABIChecker: add a test for -use-interface-for-module flag --- test/api-digester/use-interface-for.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test/api-digester/use-interface-for.swift diff --git a/test/api-digester/use-interface-for.swift b/test/api-digester/use-interface-for.swift new file mode 100644 index 0000000000000..6399084893092 --- /dev/null +++ b/test/api-digester/use-interface-for.swift @@ -0,0 +1,20 @@ +// REQUIRES: VENDOR=apple + +// RUN: %empty-directory(%t.mod) +// RUN: %empty-directory(%t.sdk) +// RUN: %empty-directory(%t.module-cache) + +// RUN: echo "public func foo() {}" > %t.swift + +// RUN: %target-swift-frontend -emit-module -emit-module-interface-path %t.mod/cake.swiftinterface %t.swift %clang-importer-sdk-nosource -parse-as-library -enable-library-evolution -disable-objc-attr-requires-foundation-module -module-cache-path %t.module-cache -emit-module-path %t.mod/cake.swiftmodule -module-name cake -swift-version 5 + +// Step 1: we should be able to load if we prefer cake.swiftinterface +// RUN: %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail -use-interface-for-module cake + +// RUN: echo "Swift Syntax Error" >> %t.mod/cake.swiftinterface + +// Step 2: we shouldn't be able to load if we prefer cake.swiftinterface and cake.swiftinterface is broken +// RUN: not %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail -use-interface-for-module cake + +// Step 3: we should be able to load if we don't prefer cake.swiftinterface +// RUN: %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail From d82a767e1396e103c0186564f1e7105a9e5a59ba Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 25 Aug 2020 16:02:21 -0700 Subject: [PATCH 334/663] SIL: Add a SILFunction::Purpose for global init once functions --- include/swift/SIL/SILFunction.h | 5 +++++ lib/SIL/IR/SILPrinter.cpp | 3 +++ lib/SIL/Parser/ParseSIL.cpp | 2 ++ lib/SILGen/SILGen.cpp | 1 + lib/Serialization/ModuleFormat.h | 2 +- test/SILGen/default_arguments.swift | 2 +- test/SILGen/global_resilience.swift | 4 ++-- test/SILGen/lazy_globals.swift | 8 ++++---- test/SILGen/lazy_globals_multiple_vars.swift | 6 +++--- test/SILGen/observers.swift | 2 +- test/SILOptimizer/access_marker_verify.swift | 6 +++--- 11 files changed, 26 insertions(+), 15 deletions(-) diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 5297539e43494..ec81558ab3179 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -121,6 +121,7 @@ class SILFunction enum class Purpose : uint8_t { None, GlobalInit, + GlobalInitOnceFunction, LazyPropertyGetter }; @@ -832,6 +833,10 @@ class SILFunction /// function itself does not need this attribute. It is private and only /// called within the addressor. bool isGlobalInit() const { return specialPurpose == Purpose::GlobalInit; } + + bool isGlobalInitOnceFunction() const { + return specialPurpose == Purpose::GlobalInitOnceFunction; + } bool isLazyPropertyGetter() const { return specialPurpose == Purpose::LazyPropertyGetter; diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 52d038ec240a9..17c3810556b77 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2606,6 +2606,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { case SILFunction::Purpose::GlobalInit: OS << "[global_init] "; break; + case SILFunction::Purpose::GlobalInitOnceFunction: + OS << "[global_init_once_fn] "; + break; case SILFunction::Purpose::LazyPropertyGetter: OS << "[lazy_getter] "; break; diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index f70112cbcdaad..f12b216fe0802 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -961,6 +961,8 @@ static bool parseDeclSILOptional(bool *isTransparent, *specialPurpose = SILFunction::Purpose::GlobalInit; else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter") *specialPurpose = SILFunction::Purpose::LazyPropertyGetter; + else if (specialPurpose && SP.P.Tok.getText() == "global_init_once_fn") + *specialPurpose = SILFunction::Purpose::GlobalInitOnceFunction; else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") { if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF()) SP.P.diagnose(SP.P.Tok, diag::attr_unsupported_on_target, diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index dffd4c3b8dfdf..883a43f0f2e6e 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1366,6 +1366,7 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, auto *f = builder.createFunction( SILLinkage::Private, funcName, initSILType, nullptr, SILLocation(binding), IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic); + f->setSpecialPurpose(SILFunction::Purpose::GlobalInitOnceFunction); f->setDebugScope(new (M) SILDebugScope(RegularLocation(binding), f)); auto dc = binding->getDeclContext(); SILGenFunction(*this, *f, dc).emitLazyGlobalInitializer(binding, pbdEntry); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 50a000ccb62ae..2b95150e58ff2 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 574; // reapply isUserAccessible +const uint16_t SWIFTMODULE_VERSION_MINOR = 575; // GlobalInitOnceFunction SILFunction purpose /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift index 8fc06fb8ed67a..94450cf10b7a9 100644 --- a/test/SILGen/default_arguments.swift +++ b/test/SILGen/default_arguments.swift @@ -156,7 +156,7 @@ class Foo { return x } - // CHECK-LABEL: sil private [ossa] @globalinit_33_E52D764B1F2009F2390B2B8DF62DAEB8_func0 + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_33_E52D764B1F2009F2390B2B8DF62DAEB8_func0 // CHECK: string_literal utf8 "Foo" static let x = Foo(int:0) diff --git a/test/SILGen/global_resilience.swift b/test/SILGen/global_resilience.swift index 78b425a9ed684..ee01a547e3b4e 100644 --- a/test/SILGen/global_resilience.swift +++ b/test/SILGen/global_resilience.swift @@ -43,7 +43,7 @@ public var myEmptyGlobal = MyEmptyStruct() // Mutable addressor for fixed-layout global -// CHECK-LABEL: sil private [ossa] @globalinit_{{.*}}_func1 +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_{{.*}}_func1 // CHECK: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return @@ -52,7 +52,7 @@ public var myEmptyGlobal = MyEmptyStruct() // CHECK: global_addr @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return -// CHECK-OPT-LABEL: sil private @globalinit_{{.*}}_func1 +// CHECK-OPT-LABEL: sil private [global_init_once_fn] @globalinit_{{.*}}_func1 // CHECK-OPT: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK-OPT: return diff --git a/test/SILGen/lazy_globals.swift b/test/SILGen/lazy_globals.swift index 4e1cc299c3468..c772aa7a2bd27 100644 --- a/test/SILGen/lazy_globals.swift +++ b/test/SILGen/lazy_globals.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func0 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T:.*]]_func0 : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals1xSiv // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals1xSivp : $*Int // CHECK: store {{%.*}} to [trivial] [[XADDR]] : $*Int @@ -16,7 +16,7 @@ // CHECK: } var x: Int = 0 -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func1 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T:.*]]_func1 : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3FooV3fooSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3FooV3fooSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -40,7 +40,7 @@ struct Foo { static var initialized: Int = 57 } -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func3 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T:.*]]_func3 : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3BarO3barSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3BarO3barSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -63,7 +63,7 @@ enum Bar { func f() -> (Int, Int) { return (1, 2) } -// CHECK: sil private [ossa] @globalinit_[[T]]_func4 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T]]_func4 : $@convention(c) () -> () { // CHECK: function_ref @$s12lazy_globals1fSi_SityF : $@convention(thin) () -> (Int, Int) // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals2a1Sivau : $@convention(thin) () -> Builtin.RawPointer // CHECK: function_ref @globalinit_[[T]]_func4 : $@convention(c) () -> () diff --git a/test/SILGen/lazy_globals_multiple_vars.swift b/test/SILGen/lazy_globals_multiple_vars.swift index 0c415d5c20231..bad5e0b41e1cc 100644 --- a/test/SILGen/lazy_globals_multiple_vars.swift +++ b/test/SILGen/lazy_globals_multiple_vars.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [ossa] [[INIT_A_B:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_A_B:@globalinit_.*]] : // CHECK: alloc_global @$s26lazy_globals_multiple_vars1aSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1aSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1bSiv @@ -13,7 +13,7 @@ // CHECK: function_ref [[INIT_A_B]] var (a, b) = (1, 2) -// CHECK: sil private [ossa] [[INIT_C:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_C:@globalinit_.*]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1cSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1cSiv @@ -21,7 +21,7 @@ var (a, b) = (1, 2) // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1cSivau // CHECK: global_addr [[TOKEN_C:@globalinit_.*]] : // CHECK: function_ref [[INIT_C]] -// CHECK: sil private [ossa] [[INIT_D:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_D:@globalinit_.*]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1dSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1dSiv diff --git a/test/SILGen/observers.swift b/test/SILGen/observers.swift index 3051c0a1126c7..22ac63b2a603e 100644 --- a/test/SILGen/observers.swift +++ b/test/SILGen/observers.swift @@ -171,7 +171,7 @@ public struct DidSetWillSetTests { var global_observing_property : Int = zero { // The variable is initialized with "zero". - // CHECK-LABEL: sil private [ossa] @globalinit_{{.*}}_func1 : $@convention(c) () -> () { + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_{{.*}}_func1 : $@convention(c) () -> () { // CHECK: bb0: // CHECK-NEXT: alloc_global @$s9observers25global_observing_propertySiv // CHECK-NEXT: %1 = global_addr @$s9observers25global_observing_propertySivp : $*Int diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift index 1ed6f62f84fdd..af14c54be2fcf 100644 --- a/test/SILOptimizer/access_marker_verify.swift +++ b/test/SILOptimizer/access_marker_verify.swift @@ -627,7 +627,7 @@ func testShims() -> UInt32 { // --- global variable initialization. var globalString1 = "⓪" // start non-empty -// CHECK-LABEL: sil private [ossa] @globalinit_33_{{.*}}_func0 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_33_{{.*}}_func0 : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString1SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString1SSvp : $*String // CHECK: apply @@ -637,7 +637,7 @@ var globalString1 = "⓪" // start non-empty // CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func0' var globalString2 = globalString1 -// CHECK-LABEL: sil private [ossa] @globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1 : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString2SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString2SSvp : $*String // CHECK: apply @@ -1037,7 +1037,7 @@ func testPointerInit(x: Int, y: UnsafeMutablePointer) { class testInitExistentialGlobal { static var testProperty: P = StructP() } -// CHECK-LABEL: sil private [ossa] @globalinit{{.*}} : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit{{.*}} : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ // CHECK: [[GADR:%.*]] = global_addr @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ : $*P // CHECK: %{{.*}} = apply %{{.*}}({{.*}}) : $@convention(method) (@thin StructP.Type) -> StructP From f74a3b47fca9efa3c0d0005c63f5ae97afe918b9 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 25 Aug 2020 13:29:18 -0700 Subject: [PATCH 335/663] [SIL] Added async flag to SILExtInfo. --- include/swift/AST/ExtInfo.h | 26 +++++++++++++------ include/swift/AST/Types.h | 4 +-- include/swift/Demangling/TypeDecoder.h | 25 +++++++++++++----- lib/AST/ASTDemangler.cpp | 2 +- lib/AST/ASTPrinter.cpp | 3 +++ lib/SILGen/SILGen.cpp | 1 + lib/SILOptimizer/Transforms/Outliner.cpp | 3 ++- .../UtilityPasses/BugReducerTester.cpp | 3 ++- lib/Sema/TypeCheckType.cpp | 5 ++-- lib/Serialization/Deserialization.cpp | 3 ++- test/SIL/Parser/async.sil | 2 +- test/SIL/Serialization/basic.sil | 2 +- 12 files changed, 53 insertions(+), 26 deletions(-) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index a19023f621042..51592181aabf2 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -495,16 +495,17 @@ class SILExtInfoBuilder { // If bits are added or removed, then TypeBase::SILFunctionTypeBits // and NumMaskBits must be updated, and they must match. - // |representation|pseudogeneric| noescape |differentiability| - // | 0 .. 3 | 4 | 5 | 6 .. 7 | + // |representation|pseudogeneric| noescape | async | differentiability| + // | 0 .. 3 | 4 | 5 | 6 | 7 .. 8 | // enum : unsigned { RepresentationMask = 0xF << 0, PseudogenericMask = 1 << 4, NoEscapeMask = 1 << 5, - DifferentiabilityMaskOffset = 6, + AsyncMask = 1 << 6, + DifferentiabilityMaskOffset = 7, DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset, - NumMaskBits = 8 + NumMaskBits = 9 }; unsigned bits; // Naturally sized for speed. @@ -523,10 +524,11 @@ class SILExtInfoBuilder { // Constructor for polymorphic type. SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape, - DifferentiabilityKind diffKind, const clang::Type *type) + bool isAsync, DifferentiabilityKind diffKind, + const clang::Type *type) : SILExtInfoBuilder( ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) | - (isNoEscape ? NoEscapeMask : 0) | + (isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) | (((unsigned)diffKind << DifferentiabilityMaskOffset) & DifferentiabilityMask), ClangTypeInfo(type)) {} @@ -552,6 +554,8 @@ class SILExtInfoBuilder { // Is this function guaranteed to be no-escape by the type system? constexpr bool isNoEscape() const { return bits & NoEscapeMask; } + constexpr bool isAsync() const { return bits & AsyncMask; } + constexpr DifferentiabilityKind getDifferentiabilityKind() const { return DifferentiabilityKind((bits & DifferentiabilityMask) >> DifferentiabilityMaskOffset); @@ -616,6 +620,10 @@ class SILExtInfoBuilder { : (bits & ~NoEscapeMask), clangTypeInfo); } + SILExtInfoBuilder withAsync(bool isAsync = true) const { + return SILExtInfoBuilder(isAsync ? (bits | AsyncMask) : (bits & ~AsyncMask), + clangTypeInfo); + } SILExtInfoBuilder withDifferentiabilityKind(DifferentiabilityKind differentiability) const { return SILExtInfoBuilder( @@ -657,8 +665,8 @@ class SILExtInfo { static SILExtInfo getThin() { return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false, - false, DifferentiabilityKind::NonDifferentiable, - nullptr) + false, false, + DifferentiabilityKind::NonDifferentiable, nullptr) .build(); } @@ -681,6 +689,8 @@ class SILExtInfo { constexpr bool isNoEscape() const { return builder.isNoEscape(); } + constexpr bool isAsync() const { return builder.isAsync(); } + constexpr DifferentiabilityKind getDifferentiabilityKind() const { return builder.getDifferentiabilityKind(); } diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 21e9a5ccd37f6..1dd1aed9bd772 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -308,7 +308,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { protected: enum { NumAFTExtInfoBits = 9 }; - enum { NumSILExtInfoBits = 8 }; + enum { NumSILExtInfoBits = 9 }; union { uint64_t OpaqueBits; SWIFT_INLINE_BITFIELD_BASE(TypeBase, bitmax(NumTypeKindBits,8) + @@ -4046,7 +4046,7 @@ class SILFunctionType final return SILCoroutineKind(Bits.SILFunctionType.CoroutineKind); } - bool isAsync() const { return Bits.SILFunctionType.IsAsync; } + bool isAsync() const { return getExtInfo().isAsync(); } /// Return the array of all the yields. ArrayRef getYields() const { diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index e591e978dccd1..1726133027988 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -238,49 +238,60 @@ class ImplFunctionTypeFlags { unsigned Rep : 3; unsigned Pseudogeneric : 1; unsigned Escaping : 1; + unsigned Async : 1; unsigned DifferentiabilityKind : 2; public: ImplFunctionTypeFlags() - : Rep(0), Pseudogeneric(0), Escaping(0), DifferentiabilityKind(0) {} + : Rep(0), Pseudogeneric(0), Escaping(0), Async(0), + DifferentiabilityKind(0) {} ImplFunctionTypeFlags(ImplFunctionRepresentation rep, bool pseudogeneric, - bool noescape, + bool noescape, bool async, ImplFunctionDifferentiabilityKind diffKind) : Rep(unsigned(rep)), Pseudogeneric(pseudogeneric), Escaping(noescape), - DifferentiabilityKind(unsigned(diffKind)) {} + Async(async), DifferentiabilityKind(unsigned(diffKind)) {} ImplFunctionTypeFlags withRepresentation(ImplFunctionRepresentation rep) const { return ImplFunctionTypeFlags( - rep, Pseudogeneric, Escaping, + rep, Pseudogeneric, Escaping, Async, + ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); + } + + ImplFunctionTypeFlags + withAsync() const { + return ImplFunctionTypeFlags( + ImplFunctionRepresentation(Rep), Pseudogeneric, Escaping, true, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withEscaping() const { return ImplFunctionTypeFlags( - ImplFunctionRepresentation(Rep), Pseudogeneric, true, + ImplFunctionRepresentation(Rep), Pseudogeneric, true, Async, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withPseudogeneric() const { return ImplFunctionTypeFlags( - ImplFunctionRepresentation(Rep), true, Escaping, + ImplFunctionRepresentation(Rep), true, Escaping, Async, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withDifferentiabilityKind(ImplFunctionDifferentiabilityKind diffKind) const { return ImplFunctionTypeFlags(ImplFunctionRepresentation(Rep), Pseudogeneric, - Escaping, diffKind); + Escaping, Async, diffKind); } ImplFunctionRepresentation getRepresentation() const { return ImplFunctionRepresentation(Rep); } + bool isAsync() const { return Async; } + bool isEscaping() const { return Escaping; } bool isPseudogeneric() const { return Pseudogeneric; } diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 44d32c84a7a7d..327b401cd5df8 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -530,7 +530,7 @@ Type ASTBuilder::createImplFunctionType( // [TODO: Store-SIL-Clang-type] auto einfo = SILExtInfoBuilder(representation, flags.isPseudogeneric(), - !flags.isEscaping(), diffKind, + !flags.isEscaping(), flags.isAsync(), diffKind, /*clangFunctionType*/ nullptr) .build(); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index aff1100a37bf9..5b4d41700d3e0 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4133,6 +4133,9 @@ class TypePrinter : public TypeVisitor { if (info.isNoEscape()) { Printer.printSimpleAttr("@noescape") << " "; } + if (info.isAsync()) { + Printer.printSimpleAttr("@async") << " "; + } } void visitAnyFunctionTypeParams(ArrayRef Params, diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index cd36b343f0e58..4154b9e9c4ca8 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -415,6 +415,7 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, SILFunctionType::ExtInfoBuilder(SILFunctionTypeRepresentation::Thin, /*pseudogeneric*/ false, /*non-escaping*/ false, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index e052a6b000f3c..b5a89537fbe0e 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -298,7 +298,7 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { auto ExtInfo = SILFunctionType::ExtInfoBuilder( SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); auto FunctionType = SILFunctionType::get( @@ -1181,6 +1181,7 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { SILFunctionType::ExtInfoBuilder(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, /*noescape*/ false, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index a8f823e584d5a..9ef7e2d70befd 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -86,7 +86,8 @@ class BugReducerTester : public SILFunctionTransform { nullptr, SILFunctionType::ExtInfoBuilder( SILFunctionType::Representation::Thin, false /*isPseudoGeneric*/, - false /*noescape*/, DifferentiabilityKind::NonDifferentiable, + false /*noescape*/, false /*async*/, + DifferentiabilityKind::NonDifferentiable, nullptr /*clangFunctionType*/) .build(), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8ec5b7a9f942f..a3845b07b62ae 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2146,8 +2146,6 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, SILFunctionType::Representation rep; TypeRepr *witnessMethodProtocol = nullptr; - auto isAsync = attrs.has(TAK_async); - auto coroutineKind = SILCoroutineKind::None; if (attrs.has(TAK_yield_once)) { coroutineKind = SILCoroutineKind::YieldOnce; @@ -2226,7 +2224,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // [TODO: Store-SIL-Clang-type] auto extInfo = SILFunctionType::ExtInfoBuilder( rep, attrs.has(TAK_pseudogeneric), - attrs.has(TAK_noescape), diffKind, nullptr) + attrs.has(TAK_noescape), attrs.has(TAK_async), + diffKind, nullptr) .build(); ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index a2b83b1faaf00..75b27d0883ec2 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5419,7 +5419,8 @@ class TypeDeserializer { auto extInfo = SILFunctionType::ExtInfoBuilder(*representation, pseudogeneric, - noescape, *diffKind, clangFunctionType) + noescape, async, *diffKind, + clangFunctionType) .build(); // Process the coroutine kind. diff --git a/test/SIL/Parser/async.sil b/test/SIL/Parser/async.sil index 32cfdebb32c0f..f65cee1ca6e16 100644 --- a/test/SIL/Parser/async.sil +++ b/test/SIL/Parser/async.sil @@ -16,7 +16,7 @@ bb0(%int : $Builtin.Int32): return %0 : $() } -// CHECK: sil @async_test : $@async +// CHECK: sil @async_test : $@convention(thin) @async sil @async_test : $@async () -> () { bb0: %0 = tuple () diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil index 1d9f1de1a810e..f6950e30ab2a5 100644 --- a/test/SIL/Serialization/basic.sil +++ b/test/SIL/Serialization/basic.sil @@ -15,7 +15,7 @@ bb0(%0 : @guaranteed $Builtin.NativeObject): return undef : $() } -// CHECK-LABEL: sil @async_test : $@async @convention(thin) +// CHECK-LABEL: sil @async_test : $@convention(thin) @async sil @async_test : $@async () -> () { bb0: %0 = tuple () From 6d6165a9db02dc98c037947bdb91071bf5104dcf Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 25 Aug 2020 17:43:27 -0700 Subject: [PATCH 336/663] SILOptimizer: Recognize globalinit once functions using an attribute instead of symbol name matching --- lib/SIL/IR/SILGlobalVariable.cpp | 2 +- lib/SILOptimizer/ARC/ARCLoopOpts.cpp | 2 +- lib/SILOptimizer/ARC/ARCSequenceOpts.cpp | 4 ++-- lib/SILOptimizer/IPO/GlobalOpt.cpp | 2 +- test/SILOptimizer/globalopt_trivial_nontrivial.sil | 6 +++--- test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil | 6 +++--- test/SILOptimizer/static_initializer.sil | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index 609a8318b153d..85407811bae76 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -272,7 +272,7 @@ SILFunction *swift::findInitializer(SILFunction *AddrF, if (!CallToOnce) return nullptr; SILFunction *callee = getCalleeOfOnceCall(CallToOnce); - if (!callee->getName().startswith("globalinit_")) + if (!callee->isGlobalInitOnceFunction()) return nullptr; return callee; } diff --git a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp index 2cadf6426c013..aa54592497e51 100644 --- a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp @@ -47,7 +47,7 @@ class ARCLoopOpts : public SILFunctionTransform { return; // Skip global init functions. - if (F->getName().startswith("globalinit_")) + if (F->isGlobalInitOnceFunction()) return; auto *LA = getAnalysis(); diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index fa0602b04bd4f..f628be8b5b29c 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -183,7 +183,7 @@ processFunctionWithoutLoopSupport(SILFunction &F, bool FreezePostDomReleases, // globalinit_func. Since that is not *that* interesting from an ARC // perspective (i.e. no ref count operations in a loop), disable it on such // functions temporarily in order to unblock others. This should be removed. - if (F.getName().startswith("globalinit_")) + if (F.isGlobalInitOnceFunction()) return false; LLVM_DEBUG(llvm::dbgs() << "***** Processing " << F.getName() << " *****\n"); @@ -231,7 +231,7 @@ static bool processFunctionWithLoopSupport( // globalinit_func. Since that is not *that* interesting from an ARC // perspective (i.e. no ref count operations in a loop), disable it on such // functions temporarily in order to unblock others. This should be removed. - if (F.getName().startswith("globalinit_")) + if (F.isGlobalInitOnceFunction()) return false; LLVM_DEBUG(llvm::dbgs() << "***** Processing " << F.getName() << " *****\n"); diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index 113d71ccb32b8..1c34038499262 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -260,7 +260,7 @@ void SILGlobalOpt::collectOnceCall(BuiltinInst *BI) { UnhandledOnceCallee = true; return; } - if (!Callee->getName().startswith("globalinit_")) + if (!Callee->isGlobalInitOnceFunction()) return; // We currently disable optimizing the initializer if a globalinit_func diff --git a/test/SILOptimizer/globalopt_trivial_nontrivial.sil b/test/SILOptimizer/globalopt_trivial_nontrivial.sil index 3625c10946211..8f094f633febb 100644 --- a/test/SILOptimizer/globalopt_trivial_nontrivial.sil +++ b/test/SILOptimizer/globalopt_trivial_nontrivial.sil @@ -38,7 +38,7 @@ sil_global private @globalinit_nontrivialglobal_token : $Builtin.Word sil_global hidden [let] @$nontrivialglobal : $TClass -sil private @globalinit_trivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_trivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$trivialglobal %1 = global_addr @$trivialglobal : $*TStruct @@ -83,13 +83,13 @@ bb0: return %4 : $Int32 } -// CHECK-LABEL: sil private @globalinit_nontrivialglobal_func : +// CHECK-LABEL: sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : // CHECK: alloc_global @$nontrivialglobal // CHECK: [[GLOBL_ADDR:%.*]] = global_addr @$nontrivialglobal : $*TClass // CHECK: [[REF:%.*]] = alloc_ref $TClass // CHECK: store [[REF]] to [[GLOBL_ADDR]] : $*TClass // CHECK: } // end sil function 'globalinit_nontrivialglobal_func' -sil private @globalinit_nontrivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$nontrivialglobal %1 = global_addr @$nontrivialglobal : $*TClass diff --git a/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil b/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil index 182210cb2671e..433aff21f011f 100644 --- a/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil +++ b/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil @@ -32,7 +32,7 @@ sil_global private @globalinit_nontrivialglobal_token : $Builtin.Word sil_global hidden [let] @$nontrivialglobal : $TClass -sil private [ossa] @globalinit_trivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] [ossa] @globalinit_trivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$trivialglobal %1 = global_addr @$trivialglobal : $*TStruct @@ -75,13 +75,13 @@ bb0: return %4 : $Int32 } -// CHECK-LABEL: sil private [ossa] @globalinit_nontrivialglobal_func : +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_nontrivialglobal_func : // CHECK: alloc_global @$nontrivialglobal // CHECK: [[GLOBL_ADDR:%.*]] = global_addr @$nontrivialglobal : $*TClass // CHECK: [[REF:%.*]] = alloc_ref $TClass // CHECK: store [[REF]] to [init] [[GLOBL_ADDR]] : $*TClass // CHECK: } // end sil function 'globalinit_nontrivialglobal_func' -sil private [ossa] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] [ossa] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$nontrivialglobal %1 = global_addr @$nontrivialglobal : $*TClass diff --git a/test/SILOptimizer/static_initializer.sil b/test/SILOptimizer/static_initializer.sil index bcdb29794c702..dbc5e28526a4f 100644 --- a/test/SILOptimizer/static_initializer.sil +++ b/test/SILOptimizer/static_initializer.sil @@ -25,8 +25,8 @@ sil_global private @globalinit_token0 : $Builtin.Word // CHECK-NEXT: } sil_global @_Tv2ch1xSi : $Outer -// CHECK-LABEL: sil private @globalinit_func0 : $@convention(c) () -> () { -sil private @globalinit_func0 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] @globalinit_func0 : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_func0 : $@convention(c) () -> () { bb0: %0 = global_addr @_Tv2ch1xSi : $*Outer %1 = integer_literal $Builtin.Int32, 2 From 79b0a7ef75ba74a7ecb802d958c3db1aa0a6fb8d Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Wed, 26 Aug 2020 02:05:29 +0100 Subject: [PATCH 337/663] [CSDiagnostics] Emit fix-its to insert requirement stubs for missing protocols in context (#33628) * [CSDiagnostics] Emit fix-its to insert requirement stubs in editor mode for missing protocols in context * [CSDiagnostics] Only include missing requirements in stub fix-it for missing protocols in context The conforming type may already have declarations that could satisfy a requirement, so we shouldn't include it in the fix-it --- include/swift/AST/ProtocolConformance.h | 17 +++---- lib/Sema/CSDiagnostics.cpp | 35 ++++++++++++++- .../fixits_missing_protocols_in_context.swift | 45 +++++++++++++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 test/decl/protocol/fixits_missing_protocols_in_context.swift diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index 1136fb5be73cd..1f61cdf438175 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -465,21 +465,22 @@ class NormalProtocolConformance : public RootProtocolConformance, uint64_t LoaderContextData; friend class ASTContext; + void resolveLazyInfo() const; + + void differenceAndStoreConditionalRequirements() const; + +public: NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol, SourceLoc loc, DeclContext *dc, ProtocolConformanceState state) - : RootProtocolConformance(ProtocolConformanceKind::Normal, conformingType), - ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(dc, false) - { + : RootProtocolConformance(ProtocolConformanceKind::Normal, + conformingType), + ProtocolAndState(protocol, state), Loc(loc), + ContextAndInvalid(dc, false) { assert(!conformingType->hasArchetype() && "ProtocolConformances should store interface types"); } - void resolveLazyInfo() const; - - void differenceAndStoreConditionalRequirements() const; - -public: /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index ec52d0ec612ad..4bef05bd9c4eb 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -17,8 +17,10 @@ #include "CSDiagnostics.h" #include "ConstraintSystem.h" #include "MiscDiagnostics.h" +#include "TypeCheckProtocol.h" #include "TypoCorrection.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" @@ -2768,9 +2770,11 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // Let's build a list of protocols that the context does not conform to. SmallVector missingProtoTypeStrings; + SmallVector missingProtocols; for (auto protocol : layout.getProtocols()) { if (!TypeChecker::conformsToProtocol(fromType, protocol->getDecl(), getDC())) { missingProtoTypeStrings.push_back(protocol->getString()); + missingProtocols.push_back(protocol->getDecl()); } } @@ -2792,8 +2796,6 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // Emit a diagnostic to inform the user that they need to conform to the // missing protocols. - // - // TODO: Maybe also insert the requirement stubs? auto conformanceDiag = emitDiagnostic(diag::assign_protocol_conformance_fix_it, unwrappedToType, nominal->getDescriptiveKind(), fromType); @@ -2808,6 +2810,35 @@ bool ContextualFailure::tryProtocolConformanceFixIt( conformanceDiag.fixItInsert(nameEndLoc, ": " + protoString); } + // Emit fix-its to insert requirement stubs if we're in editor mode. + if (!getASTContext().LangOpts.DiagnosticsEditorMode) { + return true; + } + + { + llvm::SmallString<128> Text; + llvm::raw_svector_ostream SS(Text); + llvm::SetVector missingWitnesses; + for (auto protocol : missingProtocols) { + auto conformance = NormalProtocolConformance( + nominal->getDeclaredType(), protocol, SourceLoc(), nominal, + ProtocolConformanceState::Incomplete); + ConformanceChecker checker(getASTContext(), &conformance, + missingWitnesses); + checker.resolveValueWitnesses(); + checker.resolveTypeWitnesses(); + } + + for (auto decl : missingWitnesses) { + swift::printRequirementStub(decl, nominal, nominal->getDeclaredType(), + nominal->getStartLoc(), SS); + } + + if (!Text.empty()) { + conformanceDiag.fixItInsertAfter(nominal->getBraces().Start, Text.str()); + } + } + return true; } diff --git a/test/decl/protocol/fixits_missing_protocols_in_context.swift b/test/decl/protocol/fixits_missing_protocols_in_context.swift new file mode 100644 index 0000000000000..0511266896062 --- /dev/null +++ b/test/decl/protocol/fixits_missing_protocols_in_context.swift @@ -0,0 +1,45 @@ +// RUN: %target-swift-frontend -typecheck -diagnostics-editor-mode -verify %s + +// Test that we emit fix-its to insert requirement stubs for the missing protocol conformance, in addition to adding the conformance. + +protocol P { + func method() + var property: Int { get } +} + +class C { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C'}} {{8-8=: P}} {{10-10=\n func method() {\n <#code#>\n \}\n\n var property: Int\n}} + } +} + +// Test that we don't emit fix-it to insert a requirement stub if there is already a satisfying witness. + +class C1 { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C1' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C1'}} {{9-9=: P}} {{11-11=\n var property: Int\n}} + } + + func method() {} +} + +class C2 { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C2' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C2'}} {{9-9=: P}} + } + + func method() {} + var property: Int = 0 +} From c44047769029df67c9e2122400dc6a2acfa40d40 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 25 Aug 2020 23:47:58 -0700 Subject: [PATCH 338/663] [NFC] [ModuleTrace] Add negative test case for cycles in trace emission (ep2). Context: rdar://67704000. --- .../ComplexModuleGraph2/{ => DaemonKit}/DaemonKit.h | 2 ++ .../DaemonKit/ViolateSecondLawOfThermodynamics.h | 5 +++++ .../ComplexModuleGraph2/module.modulemap | 6 +++++- test/Driver/loaded_module_trace_directness_2.swift | 12 +++++++----- 4 files changed, 19 insertions(+), 6 deletions(-) rename test/Driver/Inputs/imported_modules/ComplexModuleGraph2/{ => DaemonKit}/DaemonKit.h (57%) create mode 100644 test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/ViolateSecondLawOfThermodynamics.h diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/DaemonKit.h similarity index 57% rename from test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit.h rename to test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/DaemonKit.h index bb28f0606b6a3..7a4cc1d8c8866 100644 --- a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit.h +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/DaemonKit.h @@ -1,3 +1,5 @@ +#import + #import struct DaemonPair { diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/ViolateSecondLawOfThermodynamics.h b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/ViolateSecondLawOfThermodynamics.h new file mode 100644 index 0000000000000..2850f0f6f424c --- /dev/null +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/DaemonKit/ViolateSecondLawOfThermodynamics.h @@ -0,0 +1,5 @@ +#import + +struct MaxwellsDaemon { + Runner *doorOperation; +}; diff --git a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap index d0673487e9836..6fee43771483d 100644 --- a/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap +++ b/test/Driver/Inputs/imported_modules/ComplexModuleGraph2/module.modulemap @@ -14,7 +14,11 @@ module CoreDaemon { } module DaemonKit { - header "DaemonKit.h" + umbrella header "DaemonKit/DaemonKit.h" + explicit module ViolateSecondLawOfThermodynamics { + header "DaemonKit/ViolateSecondLawOfThermodynamics.h" + export * + } export * } diff --git a/test/Driver/loaded_module_trace_directness_2.swift b/test/Driver/loaded_module_trace_directness_2.swift index 95f06446c1df1..e0b9eabd438bd 100644 --- a/test/Driver/loaded_module_trace_directness_2.swift +++ b/test/Driver/loaded_module_trace_directness_2.swift @@ -99,14 +99,16 @@ public func runBoth(_ pair: DaemonKit.DaemonPair) { // RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV1 -module-name TestDaemonV1 -emit-loaded-module-trace-path %t/TestDaemonV1.trace.json -I %t/include // RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV1.trace.json -// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include -// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json +// FIXME: rdar://67704000 +// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV2 -module-name TestDaemonV2 -emit-loaded-module-trace-path %t/TestDaemonV2.trace.json -I %t/include +// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV2.trace.json // RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV3 -module-name TestDaemonV3 -emit-loaded-module-trace-path %t/TestDaemonV3.trace.json -I %t/include // RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV3.trace.json -// RUN: %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include -// RUN: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json +// FIXME: rdar://67704000 +// RUN: not --crash %target-swift-frontend %s -typecheck -DTestDaemon -DV4 -module-name TestDaemonV4 -emit-loaded-module-trace-path %t/TestDaemonV4.trace.json -I %t/include +// SKIP: %FileCheck %s --check-prefix=TESTDAEMON < %t/TestDaemonV4.trace.json #if TestDaemon #if V1 @@ -114,7 +116,7 @@ public func runBoth(_ pair: DaemonKit.DaemonPair) { #endif #if V2 import DaemonKit - public func noop(_: CoreDaemon.Daemon) {} + public func noop(_: CoreDaemon.Daemon, _: MaxwellsDaemon) {} #endif #if V3 import CoreDaemon From a53f3633c04630f416bdf8e8105d78a3883c83fb Mon Sep 17 00:00:00 2001 From: David Zarzycki Date: Tue, 25 Aug 2020 10:02:01 -0400 Subject: [PATCH 339/663] [IRGen] NFC: Simplify IRGenModule::defineTypeMetadata Also make `IRGenModule::getAddrOfTypeMetadata()` more clear that a GEP is being forced and optional aliasing is involved rather than imply that full metadata always requires a GEP (which it does not). --- lib/IRGen/GenDecl.cpp | 87 ++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 250519e87905f..9ac46be66bbc9 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3943,32 +3943,14 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, return cast(addr); } - /// For concrete metadata, we want to use the initializer on the - /// "full metadata", and define the "direct" address point as an alias. - TypeMetadataAddress addrKind; - unsigned adjustmentIndex; - - auto nominal = concreteType->getAnyNominal(); - - // Native Swift class metadata has a destructor before the address point. - // Foreign class metadata candidates do not, and neither does value type - // metadata. - if (nominal && isa(nominal) && - !requiresForeignTypeMetadata(nominal)) { - addrKind = TypeMetadataAddress::FullMetadata; - adjustmentIndex = MetadataAdjustmentIndex::Class; - } else { - addrKind = TypeMetadataAddress::FullMetadata; - adjustmentIndex = MetadataAdjustmentIndex::ValueType; - } - auto entity = (isPrespecialized && !irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable( *this, concreteType)) ? LinkEntity::forNoncanonicalSpecializedGenericTypeMetadata( concreteType) - : LinkEntity::forTypeMetadata(concreteType, addrKind); + : LinkEntity::forTypeMetadata(concreteType, + TypeMetadataAddress::FullMetadata); auto DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), entity.getDefaultDeclarationType(*this)->getPointerTo(), @@ -3986,30 +3968,35 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, if (link.isUsed()) addUsedGlobal(var); - // Keep type metadata around for all types. - if (nominal) + /// For concrete metadata, we want to use the initializer on the + /// "full metadata", and define the "direct" address point as an alias. + unsigned adjustmentIndex = MetadataAdjustmentIndex::ValueType; + + if (auto nominal = concreteType->getAnyNominal()) { + // Keep type metadata around for all types. addRuntimeResolvableType(nominal); - // Don't define the alias for foreign type metadata or prespecialized generic - // metadata, since neither is ABI. - if ((nominal && requiresForeignTypeMetadata(nominal)) || isPrespecialized) - return var; + // Don't define the alias for foreign type metadata or prespecialized + // generic metadata, since neither is ABI. + if (requiresForeignTypeMetadata(nominal) || isPrespecialized) + return var; - // For concrete metadata, declare the alias to its address point. - auto directEntity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::AddressPoint); + // Native Swift class metadata has a destructor before the address point. + if (isa(nominal)) { + adjustmentIndex = MetadataAdjustmentIndex::Class; + } + } - llvm::Constant *addr = var; - // Do an adjustment if necessary. - if (adjustmentIndex) { - llvm::Constant *indices[] = { + llvm::Constant *indices[] = { llvm::ConstantInt::get(Int32Ty, 0), - llvm::ConstantInt::get(Int32Ty, adjustmentIndex) - }; - addr = llvm::ConstantExpr::getInBoundsGetElementPtr(/*Ty=*/nullptr, - addr, indices); - } + llvm::ConstantInt::get(Int32Ty, adjustmentIndex)}; + auto addr = llvm::ConstantExpr::getInBoundsGetElementPtr(/*Ty=*/nullptr, var, + indices); addr = llvm::ConstantExpr::getBitCast(addr, TypeMetadataPtrTy); + + // For concrete metadata, declare the alias to its address point. + auto directEntity = LinkEntity::forTypeMetadata( + concreteType, TypeMetadataAddress::AddressPoint); return defineAlias(directEntity, addr); } @@ -4030,15 +4017,17 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, auto nominal = concreteType->getAnyNominal(); - llvm::Type *defaultVarTy; - unsigned adjustmentIndex; - bool foreign = nominal && requiresForeignTypeMetadata(nominal); + + // Foreign classes and prespecialized generic types do not use an alias into + // the full metadata and therefore require a GEP. bool fullMetadata = foreign || (concreteType->getAnyGeneric() && concreteType->getAnyGeneric()->isGenericContext()); - // Foreign classes reference the full metadata with a GEP. + llvm::Type *defaultVarTy; + unsigned adjustmentIndex; + if (fullMetadata) { defaultVarTy = FullTypeMetadataStructTy; if (concreteType->getClassOrBoundGenericClass() && !foreign) { @@ -4046,9 +4035,9 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, } else { adjustmentIndex = MetadataAdjustmentIndex::ValueType; } - // The symbol for other nominal type metadata is generated at the address - // point. } else if (nominal) { + // The symbol for native non-generic nominal type metadata is generated at + // the aliased address point (see defineTypeMetadata() above). assert(!nominal->hasClangNode()); defaultVarTy = TypeMetadataStructTy; @@ -4082,13 +4071,9 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, switch (canonicality) { case TypeMetadataCanonicality::Canonical: - if (fullMetadata) { - entity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::FullMetadata); - } else { - entity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::AddressPoint); - } + entity = LinkEntity::forTypeMetadata( + concreteType, fullMetadata ? TypeMetadataAddress::FullMetadata + : TypeMetadataAddress::AddressPoint); break; case TypeMetadataCanonicality::Noncanonical: entity = From 43fb346b6795b0885b82d7c943e33566bb4923f6 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 4 Aug 2020 17:08:46 +0900 Subject: [PATCH 340/663] [Frontend] Set up output file .swiftmodule.summary This patch focus on teaching frontend and driver to emit this file. The actual serialization and deserialization implementation will come later. --- include/swift/AST/DiagnosticsFrontend.def | 2 + include/swift/Basic/FileTypes.def | 1 + include/swift/Basic/PrimarySpecificPaths.h | 3 ++ .../swift/Basic/SupplementaryOutputPaths.h | 3 ++ include/swift/Driver/Driver.h | 5 +++ .../swift/Frontend/FrontendInputsAndOutputs.h | 1 + include/swift/Frontend/FrontendOptions.h | 1 + include/swift/Option/Options.td | 11 +++++ lib/Basic/FileTypes.cpp | 3 ++ lib/Driver/Driver.cpp | 21 ++++++++++ lib/Driver/ToolChains.cpp | 5 +++ .../ArgsToFrontendOptionsConverter.cpp | 5 +++ .../ArgsToFrontendOutputsConverter.cpp | 11 ++++- lib/Frontend/FrontendInputsAndOutputs.cpp | 6 +++ lib/Frontend/FrontendOptions.cpp | 41 +++++++++++++++++++ lib/FrontendTool/FrontendTool.cpp | 17 ++++++++ test/Driver/emit-module-summary.swift | 6 +++ test/Frontend/emit-module-summary.swift | 10 +++++ 18 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 test/Driver/emit-module-summary.swift create mode 100644 test/Frontend/emit-module-summary.swift diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 36471ecbc9d92..693518ddd4dd5 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -125,6 +125,8 @@ ERROR(error_mode_cannot_emit_module_source_info,none, "this mode does not support emitting module source info files", ()) ERROR(error_mode_cannot_emit_interface,none, "this mode does not support emitting module interface files", ()) +ERROR(error_mode_cannot_emit_module_summary,none, + "this mode does not support emitting module summary files", ()) ERROR(cannot_emit_ir_skipping_function_bodies,none, "-experimental-skip-non-inlinable-function-bodies does not support " "emitting IR", ()) diff --git a/include/swift/Basic/FileTypes.def b/include/swift/Basic/FileTypes.def index 1435813ae6e6c..2a051381ec0fe 100644 --- a/include/swift/Basic/FileTypes.def +++ b/include/swift/Basic/FileTypes.def @@ -51,6 +51,7 @@ TYPE("swiftmodule", SwiftModuleFile, "swiftmodule", "") TYPE("swiftdoc", SwiftModuleDocFile, "swiftdoc", "") TYPE("swiftinterface", SwiftModuleInterfaceFile, "swiftinterface", "") TYPE("private-swiftinterface", PrivateSwiftModuleInterfaceFile, "private.swiftinterface", "") +TYPE("swiftmodulesummary", SwiftModuleSummaryFile, "swiftmodulesummary", "") TYPE("swiftsourceinfo", SwiftSourceInfoFile, "swiftsourceinfo", "") TYPE("assembly", Assembly, "s", "") TYPE("raw-sil", RawSIL, "sil", "") diff --git a/include/swift/Basic/PrimarySpecificPaths.h b/include/swift/Basic/PrimarySpecificPaths.h index 1e73810ed61c1..f21ec9e46e9fb 100644 --- a/include/swift/Basic/PrimarySpecificPaths.h +++ b/include/swift/Basic/PrimarySpecificPaths.h @@ -49,6 +49,9 @@ class PrimarySpecificPaths { return !SupplementaryOutputs.ModuleOutputPath.empty() || !SupplementaryOutputs.ModuleDocOutputPath.empty(); } + bool haveModuleSummaryOutputPath() const { + return !SupplementaryOutputs.ModuleSummaryOutputPath.empty(); + } }; } // namespace swift diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h index c1d0494a95891..3649d4dbe7ae3 100644 --- a/include/swift/Basic/SupplementaryOutputPaths.h +++ b/include/swift/Basic/SupplementaryOutputPaths.h @@ -165,6 +165,9 @@ struct SupplementaryOutputPaths { /// name per symbol, we should eventually remove this. std::string LdAddCFilePath; + /// The path to which we should emit module summary file. + std::string ModuleSummaryOutputPath; + SupplementaryOutputPaths() = default; SupplementaryOutputPaths(const SupplementaryOutputPaths &) = default; diff --git a/include/swift/Driver/Driver.h b/include/swift/Driver/Driver.h index 5e055359d6346..d55121ea2da86 100644 --- a/include/swift/Driver/Driver.h +++ b/include/swift/Driver/Driver.h @@ -366,6 +366,11 @@ class Driver { file_types::ID fileType, CommandOutput *output) const; + void chooseModuleSummaryPath(Compilation &C, const TypeToPathMap *OutputMap, + StringRef workingDirectory, + llvm::SmallString<128> &Buf, + CommandOutput *Output) const; + void chooseRemappingOutputPath(Compilation &C, const TypeToPathMap *OutputMap, CommandOutput *Output) const; diff --git a/include/swift/Frontend/FrontendInputsAndOutputs.h b/include/swift/Frontend/FrontendInputsAndOutputs.h index 76f5ef125bc14..8f4cd7a47c63d 100644 --- a/include/swift/Frontend/FrontendInputsAndOutputs.h +++ b/include/swift/Frontend/FrontendInputsAndOutputs.h @@ -239,6 +239,7 @@ class FrontendInputsAndOutputs { bool hasModuleSourceInfoOutputPath() const; bool hasModuleInterfaceOutputPath() const; bool hasPrivateModuleInterfaceOutputPath() const; + bool hasModuleSummaryOutputPath() const; bool hasTBDPath() const; bool hasDependencyTrackerPath() const; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 724cf7e6efa31..50a6289c76f69 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -333,6 +333,7 @@ class FrontendOptions { static bool canActionEmitLoadedModuleTrace(ActionType); static bool canActionEmitModule(ActionType); static bool canActionEmitModuleDoc(ActionType); + static bool canActionEmitModuleSummary(ActionType); static bool canActionEmitInterface(ActionType); public: diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 8273359fcb97c..d560bd261ace4 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -443,6 +443,17 @@ def emit_module_path_EQ : Joined<["-"], "emit-module-path=">, ArgumentIsPath, SupplementaryOutput]>, Alias; +def emit_module_summary : + Flag<["-"], "emit-module-summary">, + Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild, + SupplementaryOutput]>, + HelpText<"Output module summary file">; +def emit_module_summary_path : + Separate<["-"], "emit-module-summary-path">, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, + ArgumentIsPath, SupplementaryOutput]>, + MetaVarName<"">, HelpText<"Output module summary file to ">; + def emit_module_interface : Flag<["-"], "emit-module-interface">, Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild, diff --git a/lib/Basic/FileTypes.cpp b/lib/Basic/FileTypes.cpp index d2c1570495dd8..f4af753c5e56a 100644 --- a/lib/Basic/FileTypes.cpp +++ b/lib/Basic/FileTypes.cpp @@ -94,6 +94,7 @@ bool file_types::isTextual(ID Id) { case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_LLVM_BC: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: @@ -138,6 +139,7 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftOverlayFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: @@ -189,6 +191,7 @@ bool file_types::isPartOfSwiftCompilation(ID Id) { case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 8d94f5ff9b7ac..80ce50e54ad05 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2004,6 +2004,7 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: case file_types::TY_JSONDependencies: @@ -2855,6 +2856,10 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA, Output.get()); } + if (isa(JA)) { + chooseModuleSummaryPath(C, OutputMap, workingDirectory, Buf, Output.get()); + } + if (isa(JA) || (isa(JA) && OI.CompilerMode == OutputInfo::Mode::SingleCompile)) { @@ -3208,6 +3213,22 @@ void Driver::chooseModuleInterfacePath(Compilation &C, const JobAction *JA, output->setAdditionalOutputForType(fileType, outputPath); } +void Driver::chooseModuleSummaryPath(Compilation &C, + const TypeToPathMap *OutputMap, + StringRef workingDirectory, + llvm::SmallString<128> &Buf, + CommandOutput *Output) const { + StringRef pathFromArgs; + if (const Arg *A = + C.getArgs().getLastArg(options::OPT_emit_module_summary_path)) { + pathFromArgs = A->getValue(); + } + + addAuxiliaryOutput(C, *Output, file_types::TY_SwiftModuleSummaryFile, + OutputMap, workingDirectory, pathFromArgs, + /*requireArg=*/options::OPT_emit_module_summary); +} + void Driver::chooseSerializedDiagnosticsPath(Compilation &C, const JobAction *JA, const TypeToPathMap *OutputMap, diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 7f669e54ba24c..9207ad9771a24 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -620,6 +620,7 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: @@ -765,6 +766,9 @@ void ToolChain::JobContext::addFrontendSupplementaryOutputArguments( "-emit-loaded-module-trace-path"); addOutputsOfType(arguments, Output, Args, file_types::TY_TBD, "-emit-tbd-path"); + addOutputsOfType(arguments, Output, Args, + file_types::TY_SwiftModuleSummaryFile, + "-emit-module-summary-path"); } ToolChain::InvocationInfo @@ -877,6 +881,7 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_BitstreamOptRecord: case file_types::TY_SwiftModuleInterfaceFile: case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftModuleSummaryFile: case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SwiftCrossImportDir: case file_types::TY_SwiftOverlayFile: diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 4e12495bb35df..769c473da9e21 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -565,6 +565,11 @@ bool ArgsToFrontendOptionsConverter::checkUnusedSupplementaryOutputPaths() Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_interface); return true; } + if (!FrontendOptions::canActionEmitModuleSummary(Opts.RequestedAction) && + Opts.InputsAndOutputs.hasModuleSummaryOutputPath()) { + Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_summary); + return true; + } return false; } diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp index ef9f200ccdd42..37b5afee63aba 100644 --- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp @@ -306,11 +306,13 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() options::OPT_emit_module_source_info_path); auto ldAddCFileOutput = getSupplementaryFilenamesFromArguments( options::OPT_emit_ldadd_cfile_path); + auto moduleSummaryOutput = getSupplementaryFilenamesFromArguments( + options::OPT_emit_module_summary_path); if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput || !dependenciesFile || !referenceDependenciesFile || !serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD || !moduleInterfaceOutput || !privateModuleInterfaceOutput || - !moduleSourceInfoOutput || !ldAddCFileOutput) { + !moduleSourceInfoOutput || !ldAddCFileOutput || !moduleSummaryOutput) { return None; } std::vector result; @@ -334,6 +336,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() sop.PrivateModuleInterfaceOutputPath = (*privateModuleInterfaceOutput)[i]; sop.ModuleSourceInfoOutputPath = (*moduleSourceInfoOutput)[i]; sop.LdAddCFilePath = (*ldAddCFileOutput)[i]; + sop.ModuleSummaryOutputPath = (*moduleSummaryOutput)[i]; result.push_back(sop); } return result; @@ -422,6 +425,10 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( OPT_emit_module_source_info, pathsFromArguments.ModuleSourceInfoOutputPath, file_types::TY_SwiftSourceInfoFile, "", defaultSupplementaryOutputPathExcludingExtension); + auto moduleSummaryOutputPath = determineSupplementaryOutputFilename( + OPT_emit_module_summary, pathsFromArguments.ModuleSummaryOutputPath, + file_types::TY_SwiftModuleSummaryFile, "", + defaultSupplementaryOutputPathExcludingExtension); // There is no non-path form of -emit-interface-path auto ModuleInterfaceOutputPath = @@ -456,6 +463,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( sop.PrivateModuleInterfaceOutputPath = PrivateModuleInterfaceOutputPath; sop.ModuleSourceInfoOutputPath = moduleSourceInfoOutputPath; sop.LdAddCFilePath = pathsFromArguments.LdAddCFilePath; + sop.ModuleSummaryOutputPath = moduleSummaryOutputPath; return sop; } @@ -537,6 +545,7 @@ createFromTypeToPathMap(const TypeToPathMap *map) { {file_types::TY_TBD, paths.TBDPath}, {file_types::TY_SwiftModuleInterfaceFile, paths.ModuleInterfaceOutputPath}, + {file_types::TY_SwiftModuleSummaryFile, paths.ModuleSummaryOutputPath}, {file_types::TY_PrivateSwiftModuleInterfaceFile, paths.PrivateModuleInterfaceOutputPath}}; for (const std::pair &typeAndString : diff --git a/lib/Frontend/FrontendInputsAndOutputs.cpp b/lib/Frontend/FrontendInputsAndOutputs.cpp index edb0bbdc6c273..52d1e823f6f1f 100644 --- a/lib/Frontend/FrontendInputsAndOutputs.cpp +++ b/lib/Frontend/FrontendInputsAndOutputs.cpp @@ -466,6 +466,12 @@ bool FrontendInputsAndOutputs::hasPrivateModuleInterfaceOutputPath() const { return outs.PrivateModuleInterfaceOutputPath; }); } +bool FrontendInputsAndOutputs::hasModuleSummaryOutputPath() const { + return hasSupplementaryOutputPath( + [](const SupplementaryOutputPaths &outs) -> const std::string & { + return outs.ModuleSummaryOutputPath; + }); +} bool FrontendInputsAndOutputs::hasTBDPath() const { return hasSupplementaryOutputPath( [](const SupplementaryOutputPaths &outs) -> const std::string & { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 83718a733666e..ea04bd2150210 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -274,6 +274,47 @@ bool FrontendOptions::canActionEmitCompiledSource(ActionType action) { return canActionEmitReferenceDependencies(action); } +bool FrontendOptions::canActionEmitModuleSummary(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::ResolveImports: + case ActionType::DumpParse: + case ActionType::DumpInterfaceHash: + case ActionType::DumpAST: + case ActionType::EmitSyntax: + case ActionType::PrintAST: + case ActionType::EmitImportedModules: + case ActionType::EmitPCH: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::DumpTypeInfo: + case ActionType::EmitSILGen: + case ActionType::EmitSIBGen: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::Typecheck: + case ActionType::MergeModules: + case ActionType::EmitModuleOnly: + case ActionType::PrintVersion: + return false; + case ActionType::EmitSIL: + case ActionType::EmitSIB: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitAssembly: + case ActionType::EmitObject: + return true; + } + llvm_unreachable("unhandled action"); +} + bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { switch (action) { case ActionType::NoneAction: diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 4221b53394e5f..bd2801b13e507 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1899,6 +1899,17 @@ static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, return Context.hadError(); } +static bool serializeModuleSummary(SILModule *SM, + const PrimarySpecificPaths &PSPs, + const ASTContext &Context) { + auto summaryOutputPath = PSPs.SupplementaryOutputs.ModuleSummaryOutputPath; + return withOutputFile(Context.Diags, summaryOutputPath, + [&](llvm::raw_ostream &out) { + out << "Some stuff"; + return false; + }); +} + static GeneratedModule generateIR(const IRGenOptions &IRGenOpts, const TBDGenOptions &TBDOpts, std::unique_ptr SM, @@ -2123,6 +2134,12 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance, if (observer) observer->performedSILProcessing(*SM); + if (PSPs.haveModuleSummaryOutputPath()) { + if (serializeModuleSummary(SM.get(), PSPs, Context)) { + return true; + } + } + if (Action == FrontendOptions::ActionType::EmitSIB) return serializeSIB(SM.get(), PSPs, Context, MSF); diff --git a/test/Driver/emit-module-summary.swift b/test/Driver/emit-module-summary.swift new file mode 100644 index 0000000000000..d1fef3299ae20 --- /dev/null +++ b/test/Driver/emit-module-summary.swift @@ -0,0 +1,6 @@ +// RUN: %empty-directory(%t) +// RUN: echo 'print("Hello, World!")' >%t/main.swift +// RUN: cd %t + +// RUN: %target-swiftc_driver -emit-sib -emit-module-summary -emit-module-summary-path %t/main.swiftmodulesummary %t/main.swift +// RUN: test -f %t/main.swiftmodulesummary diff --git a/test/Frontend/emit-module-summary.swift b/test/Frontend/emit-module-summary.swift new file mode 100644 index 0000000000000..7e69f23c95247 --- /dev/null +++ b/test/Frontend/emit-module-summary.swift @@ -0,0 +1,10 @@ +// RUN: %empty-directory(%t) +// RUN: echo 'print("Hello, World!")' >%t/main.swift +// RUN: cd %t + +// RUN: %target-swift-frontend -emit-sib -emit-module-summary-path %t/main.swiftmodulesummary %t/main.swift +// RUN: test -f %t/main.swiftmodulesummary + +// RUN: echo '"%/t/main.swift": { swiftmodulesummary: "%/t/foo.swiftmodulesummary" }' > %/t/filemap.yaml +// RUN: %target-swift-frontend -emit-sib -supplementary-output-file-map %/t/filemap.yaml %/t/main.swift +// RUN: test -f %t/foo.swiftmodulesummary From 9962f799b7efffa4eaace4af0e8e7fd8f51a0b6b Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Wed, 26 Aug 2020 11:46:13 -0400 Subject: [PATCH 341/663] [RemoteMirror] Fix potential uninitialized data access in convertChild. The else branch of the type checking code just does assert(false). When asserts are off, the code will fall through and access the uninitialized FieldInfo variable. Instead, return something sensible for this error case. --- stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 114cf058512d0..92853104c25ea 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -447,6 +447,12 @@ static swift_childinfo_t convertChild(const TypeInfo *TI, unsigned Index) { FieldInfo = &(RecordTI->getFields()[Index]); } else { assert(false && "convertChild(TI): TI must be record or enum typeinfo"); + return { + "unknown TypeInfo kind", + 0, + SWIFT_UNKNOWN, + 0, + }; } return { From bf5fb4d2bb6ca857aa4d2a932413ea77e8face7b Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 26 Aug 2020 09:56:36 -0700 Subject: [PATCH 342/663] [CodeCompletion] Don't update VFS content hash map after each completion This was not needed. The list of depenencies should not be changed during fast-completion sessions. This was also harmful because it calls stat(2) for all the dependency files. rdar://problem/67773257 --- lib/IDE/CompletionInstance.cpp | 2 -- .../CodeComplete/complete_checkdeps_vfs.swift | 29 +++++++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 2f8a6cd7040b5..1aeffb3304356 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -485,8 +485,6 @@ bool CompletionInstance::performCachedOperationIfPossible( } CachedReuseCount += 1; - cacheDependencyHashIfNeeded(CI, SM.getCodeCompletionBufferID(), - InMemoryDependencyHash); return true; } diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift index 388c09e57af33..84753c3a8c3f2 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift @@ -4,8 +4,8 @@ func foo(value: MyStruct) { // REQUIRES: shell -// RUN: DEPCHECK_INTERVAL=1 -// RUN: SLEEP_TIME=2 +// RUN: DEPCHECK_INTERVAL=2 +// RUN: SLEEP_TIME=3 // RUN: %empty-directory(%t) // RUN: %empty-directory(%t/VFS) @@ -23,7 +23,14 @@ func foo(value: MyStruct) { // RUN: -shell -- echo "### Keep" == \ // RUN: -shell -- sleep ${SLEEP_TIME} == \ -// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject_mod/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject_mod/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ + +// RUN: -shell -- echo "### Rollback without sleep" == \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ + +// RUN: -shell -- echo "### After sleep" == \ +// RUN: -shell -- sleep ${SLEEP_TIME} == \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift \ // RUN: | %FileCheck %s @@ -50,3 +57,19 @@ func foo(value: MyStruct) { // CHECK-DAG: key.description: "self" // CHECK: ] // CHECK: key.reusingastcontext: 1 + +// CHECK-LABEL: ### Rollback without sleep +// CHECK: key.results: [ +// CHECK-DAG: key.description: "myStructMethod_mod()" +// CHECK-DAG: key.description: "extensionMethod()" +// CHECK-DAG: key.description: "self" +// CHECK: ] +// CHECK: key.reusingastcontext: 1 + +// CHECK-LABEL: ### After sleep +// CHECK: key.results: [ +// CHECK-DAG: key.description: "myStructMethod()" +// CHECK-DAG: key.description: "extensionMethod()" +// CHECK-DAG: key.description: "self" +// CHECK: ] +// CHECK-NOT: key.reusingastcontext: 1 From 58604ff1bae00e9481cbbccc48b37e707c2fc48c Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Wed, 26 Aug 2020 13:24:44 -0400 Subject: [PATCH 343/663] [Runtime] Fix memory ordering on a store in ConcurrentReadableArray. --- include/swift/Runtime/Concurrent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 10269653284df..6ee42cdc29c1d 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -517,7 +517,7 @@ template struct ConcurrentReadableArray { auto *newStorage = Storage::allocate(newCapacity); if (storage) { std::copy(storage->data(), storage->data() + count, newStorage->data()); - newStorage->Count.store(count, std::memory_order_relaxed); + newStorage->Count.store(count, std::memory_order_release); FreeList.push_back(storage); } From 66e2ce691a6b77af17dfe6195b1cd057c4b9ddbd Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Wed, 26 Aug 2020 11:38:16 -0700 Subject: [PATCH 344/663] Remove apparently unnecessary filter for CMO serializing references to globalinit once variables --- lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp index ea8429c854876..ce00fdd8b8e43 100644 --- a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp +++ b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp @@ -337,9 +337,6 @@ bool CrossModuleSerializationSetup::canSerialize(SILInstruction *inst, }); return canUse; } - if (auto *GAI = dyn_cast(inst)) { - return !GAI->getReferencedGlobal()->getName().startswith("globalinit_"); - } if (auto *MI = dyn_cast(inst)) { return !MI->getMember().isForeign; } From 29c7216c6c0db7fe556a9ce223a2acc447554a8a Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 26 Aug 2020 13:07:05 -0700 Subject: [PATCH 345/663] DependenciesScanner: include search path options in PCM building commands Unlike Swift modules, building Clang PCMs requires search path options like -F and -I to look for transitive header includes because in module maps, we can only find top-level headers. rdar://67589328 --- lib/ClangImporter/ClangModuleDependencyScanner.cpp | 14 ++++++++++++++ test/ScanDependencies/batch_module_scan.swift | 1 + test/ScanDependencies/module_deps.swift | 2 -- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index ed49b5213ead5..290dd69506ed2 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -254,6 +254,20 @@ void ClangImporter::recordModuleDependencies( swiftArgs.push_back("-module-name"); swiftArgs.push_back(clangModuleDep.ModuleName); + // Pass down search paths to the -emit-module action. + // Unlike building Swift modules, we need to include all search paths to + // the clang invocation to build PCMs because transitive headers can only + // be found via search paths. Passing these headers as explicit inputs can + // be quite challenging. + for (auto &path: Impl.SwiftContext.SearchPathOpts.ImportSearchPaths) { + swiftArgs.push_back("-I"); + swiftArgs.push_back(path); + } + for (auto &path: Impl.SwiftContext.SearchPathOpts.FrameworkSearchPaths) { + swiftArgs.push_back(path.IsSystem ? "-Fsystem": "-F"); + swiftArgs.push_back(path.Path); + } + // Swift frontend option for input file path (Foo.modulemap). swiftArgs.push_back(clangModuleDep.ClangModuleMapFile); // Module-level dependencies. diff --git a/test/ScanDependencies/batch_module_scan.swift b/test/ScanDependencies/batch_module_scan.swift index 08151fc4eb6f6..4f0c173f7a99f 100644 --- a/test/ScanDependencies/batch_module_scan.swift +++ b/test/ScanDependencies/batch_module_scan.swift @@ -28,6 +28,7 @@ // CHECK-PCM-NEXT: }, // CHECK-PCM-NEXT: { // CHECK-PCM-NEXT: "modulePath": "F.pcm", +// CHECK-PCM: "-I" // CHECK-SWIFT: { // CHECK-SWIFT-NEXT: "mainModuleName": "F", diff --git a/test/ScanDependencies/module_deps.swift b/test/ScanDependencies/module_deps.swift index 7e3a62507ed99..05b6f15c322fb 100644 --- a/test/ScanDependencies/module_deps.swift +++ b/test/ScanDependencies/module_deps.swift @@ -195,9 +195,7 @@ import SubE /// --------Clang module SwiftShims // CHECK-LABEL: "modulePath": "SwiftShims.pcm", -// CHECK-NO-SEARCH-PATHS-NOT: "-I" // CHECK-NO-SEARCH-PATHS-NOT: "-sdk" -// CHECK-NO-SEARCH-PATHS-NOT: "-F" // CHECK-NO-SEARCH-PATHS-NOT: "-prebuilt-module-cache-path" // Check make-style dependencies From 82e870b8a1f7af86fedefc969c304a2c945c984c Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 26 Aug 2020 13:19:14 -0700 Subject: [PATCH 346/663] build: remove the Python 2 check The Swift build is now fully migrated to Python 3. Although it is backwards/forwards compatible, the build invokes everything with the Python3 interpreter, and the Python 2 interpreter should be unused. Remove the last reference to it. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 844fcdb251f37..a84adb0ca4636 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -914,7 +914,6 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") endif() endif() -find_package(Python2 COMPONENTS Interpreter REQUIRED) find_package(Python3 COMPONENTS Interpreter REQUIRED) # From 362a25ae84ca4f56b4dfb810b6f9ecc438c0439a Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Wed, 15 Jan 2020 16:15:34 -0800 Subject: [PATCH 347/663] [AST] Support SILFunctionType/SILBlockStorageType in ClangTypeConverter. This translation is a pre-requisite to storing Clang types in SILFunctionType. --- lib/AST/ClangTypeConverter.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index d4ccea512f069..2a08f78fb282e 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -576,12 +576,19 @@ clang::QualType ClangTypeConverter::visitFunctionType(FunctionType *type) { } clang::QualType ClangTypeConverter::visitSILFunctionType(SILFunctionType *type) { - llvm::report_fatal_error("Expected only AST types but found a SIL function."); + // We must've already computed it before if applicable. + return clang::QualType(type->getClangTypeInfo().getType(), 0); } clang::QualType ClangTypeConverter::visitSILBlockStorageType(SILBlockStorageType *type) { - llvm::report_fatal_error("Expected only AST types but found a SIL block."); + // We'll select (void)(^)(). This isn't correct for all blocks, but block + // storage type should only be converted for function signature lowering, + // where the parameter types do not matter. + auto &clangCtx = ClangASTContext; + auto fnTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy); + auto blockTy = clangCtx.getBlockPointerType(fnTy); + return clangCtx.getCanonicalType(blockTy); } clang::QualType From 78ea3de8e4e8c21528e7e60913fc466541c740ad Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 25 Aug 2020 23:29:53 -0700 Subject: [PATCH 348/663] [AST] Introduce a new type to represent a type hole in constraint system Instead of using `UnresolvedType` as a placeholder for a type hole, let's switch over to a dedicated "rich" `HoleType` which is capable of storing "originator" type - type variable or dependent member type which couldn't be resolved. This makes it easier for the solver to determine origins of a hole which helps to diagnose certain problems better. It also helps code completion to locate "expected type" of the context even when it couldn't be completely resolved. --- include/swift/AST/TypeNodes.def | 1 + include/swift/AST/Types.h | 38 ++++++++++++++++++++++++++--- lib/AST/ASTContext.cpp | 11 +++++++-- lib/AST/ASTDumper.cpp | 12 +++++++++ lib/AST/ASTMangler.cpp | 1 + lib/AST/ASTPrinter.cpp | 11 +++++++++ lib/AST/Type.cpp | 8 +++--- lib/AST/TypeWalker.cpp | 1 + lib/IRGen/IRGenDebugInfo.cpp | 1 + lib/Sema/CSSimplify.cpp | 2 ++ lib/Serialization/Serialization.cpp | 4 +++ 11 files changed, 81 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index b04f82bb9a8de..f827339dd5064 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -89,6 +89,7 @@ TYPE(Error, Type) UNCHECKED_TYPE(Unresolved, Type) +UNCHECKED_TYPE(Hole, Type) ABSTRACT_TYPE(Builtin, Type) ABSTRACT_TYPE(AnyBuiltinInteger, BuiltinType) BUILTIN_TYPE(BuiltinInteger, AnyBuiltinIntegerType) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index e55c8bf7be3d5..d5fae0c50be9f 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -148,7 +148,10 @@ class RecursiveTypeProperties { /// This type contains an OpaqueTypeArchetype. HasOpaqueArchetype = 0x400, - Last_Property = HasOpaqueArchetype + /// This type constains a type hole. + HasTypeHole = 0x800, + + Last_Property = HasTypeHole }; enum { BitWidth = countBitsUsed(Property::Last_Property) }; @@ -203,6 +206,10 @@ class RecursiveTypeProperties { /// generic type? bool hasUnboundGeneric() const { return Bits & HasUnboundGeneric; } + /// Does a type with these properties structurally contain a + /// type hole? + bool hasTypeHole() const { return Bits & HasTypeHole; } + /// Returns the set of properties present in either set. friend RecursiveTypeProperties operator|(Property lhs, Property rhs) { return RecursiveTypeProperties(unsigned(lhs) | unsigned(rhs)); @@ -574,9 +581,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { } /// Determine whether this type involves a hole. - bool hasHole() const { - return getRecursiveProperties().hasUnresolvedType(); - } + bool hasHole() const { return getRecursiveProperties().hasTypeHole(); } /// Determine whether the type involves a context-dependent archetype. bool hasArchetype() const { @@ -5728,6 +5733,31 @@ TypeVariableType : public TypeBase { }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type) +/// HoleType - This represents a placeholder type for a type variable +/// or dependent member type that cannot be resolved to a concrete type +/// because the expression is ambiguous. This type is only used by the +/// constraint solver and transformed into UnresolvedType to be used in AST. +class HoleType : public TypeBase { + using OriginatorType = + llvm::PointerUnion; + + OriginatorType Originator; + + HoleType(ASTContext &C, OriginatorType originator, + RecursiveTypeProperties properties) + : TypeBase(TypeKind::Hole, &C, properties), Originator(originator) {} + +public: + static Type get(ASTContext &ctx, OriginatorType originatorType); + + OriginatorType getOriginatorType() const { return Originator; } + + static bool classof(const TypeBase *T) { + return T->getKind() == TypeKind::Hole; + } +}; +DEFINE_EMPTY_CAN_TYPE_WRAPPER(HoleType, Type) + inline bool TypeBase::isTypeVariableOrMember() { if (is()) return true; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f3ee9197874a9..6c7e155e8b6d4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2358,6 +2358,13 @@ Type ErrorType::get(Type originalType) { return entry = new (mem) ErrorType(ctx, originalType, properties); } +Type HoleType::get(ASTContext &ctx, OriginatorType originator) { + assert(originator); + RecursiveTypeProperties properties = RecursiveTypeProperties::HasTypeHole; + auto arena = getArena(properties); + return new (ctx, arena) HoleType(ctx, originator, properties); +} + BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth, const ASTContext &C) { assert(!BitWidth.isArbitraryWidth()); @@ -2957,7 +2964,7 @@ isFunctionTypeCanonical(ArrayRef params, static RecursiveTypeProperties getGenericFunctionRecursiveProperties(ArrayRef params, Type result) { - static_assert(RecursiveTypeProperties::BitWidth == 11, + static_assert(RecursiveTypeProperties::BitWidth == 12, "revisit this if you add new recursive type properties"); RecursiveTypeProperties properties; @@ -3513,7 +3520,7 @@ CanSILFunctionType SILFunctionType::get( void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); RecursiveTypeProperties properties; - static_assert(RecursiveTypeProperties::BitWidth == 11, + static_assert(RecursiveTypeProperties::BitWidth == 12, "revisit this if you add new recursive type properties"); for (auto ¶m : params) properties |= param.getInterfaceType()->getRecursiveProperties(); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index d8352e9c62e2c..95b603206fb35 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3496,6 +3496,18 @@ namespace { TRIVIAL_TYPE_PRINTER(Unresolved, unresolved) + void visitHoleType(HoleType *T, StringRef label) { + printCommon(label, "hole_type"); + auto originatorTy = T->getOriginatorType(); + if (auto *typeVar = originatorTy.dyn_cast()) { + printRec("type_variable", typeVar); + } else { + printRec("dependent_member_type", + originatorTy.get()); + } + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitBuiltinIntegerType(BuiltinIntegerType *T, StringRef label) { printCommon(label, "builtin_integer_type"); if (T->isFixedWidth()) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index be1c4af4e0ea1..a79b63409090c 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -915,6 +915,7 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) { TypeBase *tybase = type.getPointer(); switch (type->getKind()) { case TypeKind::TypeVariable: + case TypeKind::Hole: llvm_unreachable("mangling type variable"); case TypeKind::Module: diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index de48919eab2b3..d4b1c58b95cbc 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3813,6 +3813,17 @@ class TypePrinter : public TypeVisitor { Printer << "_"; } + void visitHoleType(HoleType *T) { + if (Options.PrintTypesForDebugging) { + Printer << "<getOriginatorType(); + visit(Type(reinterpret_cast(originatorTy.getOpaqueValue()))); + Printer << ">>"; + } else { + Printer << "<>"; + } + } + #ifdef ASTPRINTER_HANDLE_BUILTINTYPE #error "ASTPRINTER_HANDLE_BUILTINTYPE should not be defined?!" #endif diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index bc7d9b780b659..6cc2cc05a01fd 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -153,9 +153,7 @@ bool TypeBase::isAny() { return isEqual(getASTContext().TheAnyType); } -bool TypeBase::isHole() { - return isEqual(getASTContext().TheUnresolvedType); -} +bool TypeBase::isHole() { return getCanonicalType()->is(); } bool TypeBase::isAnyClassReferenceType() { return getCanonicalType().isAnyClassReferenceType(); @@ -221,6 +219,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig, case TypeKind::LValue: case TypeKind::InOut: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: case TypeKind::SILToken: @@ -1149,6 +1148,7 @@ CanType TypeBase::computeCanonicalType() { case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: + case TypeKind::Hole: llvm_unreachable("these types are always canonical"); #define SUGARED_TYPE(id, parent) \ @@ -4244,6 +4244,7 @@ case TypeKind::Id: case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::GenericTypeParam: case TypeKind::SILToken: case TypeKind::Module: @@ -4983,6 +4984,7 @@ ReferenceCounting TypeBase::getReferenceCounting() { case TypeKind::LValue: case TypeKind::InOut: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: case TypeKind::SILToken: diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index f5be4e10b5223..f95bdb01366f9 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -34,6 +34,7 @@ class Traversal : public TypeVisitor bool visitErrorType(ErrorType *ty) { return false; } bool visitUnresolvedType(UnresolvedType *ty) { return false; } + bool visitHoleType(HoleType *ty) { return false; } bool visitBuiltinType(BuiltinType *ty) { return false; } bool visitTypeAliasType(TypeAliasType *ty) { if (auto parent = ty->getParent()) diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index e1cd39d903dde..65387d02719d7 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1571,6 +1571,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { case TypeKind::Unresolved: case TypeKind::LValue: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::Module: case TypeKind::SILBlockStorage: case TypeKind::SILBox: diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1608f19e49155..31921f7d626ab 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4685,6 +4685,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case TypeKind::Error: case TypeKind::Unresolved: + case TypeKind::Hole: return getTypeMatchFailure(locator); case TypeKind::GenericTypeParam: @@ -5366,6 +5367,7 @@ ConstraintSystem::simplifyConstructionConstraint( case TypeKind::Unresolved: case TypeKind::Error: + case TypeKind::Hole: return SolutionKind::Error; case TypeKind::GenericFunction: diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 20179b2876c19..5be326c2a7e5e 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3925,6 +3925,10 @@ class Serializer::TypeSerializer : public TypeVisitor { llvm_unreachable("should not serialize an invalid type"); } + void visitHoleType(const HoleType *) { + llvm_unreachable("should not serialize an invalid type"); + } + void visitModuleType(const ModuleType *) { llvm_unreachable("modules are currently not first-class values"); } From 48c976768092174f5925a6fa5fa372ab84457f80 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 26 Aug 2020 18:42:05 -0700 Subject: [PATCH 349/663] [CSApply] Make sure that hole type are not propagated to AST --- lib/Sema/CSApply.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 276974ed4ab42..b4ec32888c67c 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7662,6 +7662,8 @@ namespace { // "Mismatched types!"); assert(!exprType->hasTypeVariable() && "Should not write type variable into expression!"); + assert(!exprType->hasHole() && + "Should not write type holes into expression!"); expr->setType(exprType); if (auto kp = dyn_cast(expr)) { From d039107bdba7319f2c72169c35a06dce89020f67 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 26 Aug 2020 18:43:10 -0700 Subject: [PATCH 350/663] [ConstraintSystem] Replace use of `UnresolvedType` with specialized `HoleType` --- lib/Sema/CSBindings.cpp | 2 +- lib/Sema/CSSimplify.cpp | 18 +++++++++++++++++- lib/Sema/ConstraintSystem.cpp | 31 ++++++++++++++++++++----------- lib/Sema/ConstraintSystem.h | 5 +++-- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 8919c9e352f4f..807a86b01a85a 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -335,7 +335,7 @@ void ConstraintSystem::PotentialBindings::finalize( if (locator->isLastElement()) PotentiallyIncomplete = true; - addPotentialBinding(PotentialBinding::forHole(cs.getASTContext(), locator)); + addPotentialBinding(PotentialBinding::forHole(TypeVar, locator)); } // Let's always consider `Any` to be a last resort binding because diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 31921f7d626ab..e39a8506d361e 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4434,6 +4434,12 @@ bool ConstraintSystem::repairFailures( } case ConstraintLocator::FunctionBuilderBodyResult: { + // If result type of the body couldn't be determined + // there is going to be other fix available to diagnose + // the underlying issue. + if (lhs->isHole()) + return true; + conversionsOrFixes.push_back(ContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); break; @@ -4685,9 +4691,19 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case TypeKind::Error: case TypeKind::Unresolved: - case TypeKind::Hole: return getTypeMatchFailure(locator); + case TypeKind::Hole: { + // If it's allowed to attempt fixes, let's delegate + // decision to `repairFailures`, since depending on + // locator we might either ignore such a mismatch, + // or record a specialized fix. + if (shouldAttemptFixes()) + break; + + return getTypeMatchFailure(locator); + } + case TypeKind::GenericTypeParam: llvm_unreachable("unmapped dependent type in type checker"); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 1214740c8d1d5..be0fc64926e92 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2617,11 +2617,13 @@ Type ConstraintSystem::simplifyTypeImpl(Type type, // there will be a missing conformance fix applied in diagnostic mode, // so the concrete dependent member type is considered a "hole" in // order to continue solving. + auto memberTy = DependentMemberType::get(lookupBaseType, assocType); if (shouldAttemptFixes() && - getPhase() == ConstraintSystemPhase::Solving) - return getASTContext().TheUnresolvedType; + getPhase() == ConstraintSystemPhase::Solving) { + return HoleType::get(getASTContext(), memberTy); + } - return DependentMemberType::get(lookupBaseType, assocType); + return memberTy; } auto subs = SubstitutionMap::getProtocolSubstitutions( @@ -2653,16 +2655,23 @@ Type ConstraintSystem::simplifyType(Type type) const { } Type Solution::simplifyType(Type type) const { - if (!type->hasTypeVariable()) + if (!(type->hasTypeVariable() || type->hasHole())) return type; // Map type variables to fixed types from bindings. - return getConstraintSystem().simplifyTypeImpl(type, - [&](TypeVariableType *tvt) -> Type { - auto known = typeBindings.find(tvt); - assert(known != typeBindings.end()); - return known->second; - }); + auto &cs = getConstraintSystem(); + auto resolvedType = cs.simplifyTypeImpl( + type, [&](TypeVariableType *tvt) -> Type { return getFixedType(tvt); }); + + // Holes shouldn't be reachable through a solution, they are only + // useful to determine what went wrong exactly. + if (resolvedType->hasHole()) { + return resolvedType.transform([&](Type type) { + return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType) : type; + }); + } + + return resolvedType; } size_t Solution::getTotalMemory() const { @@ -4646,7 +4655,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization( // Determine the contextual type for the initialization. TypeLoc contextualType; if (!(isa(pattern) && !pattern->isImplicit()) && - patternType && !patternType->isHole()) { + patternType && !patternType->is()) { contextualType = TypeLoc::withoutLoc(patternType); // Only provide a TypeLoc if it makes sense to allow diagnostics. diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index bc95ed45c0b55..18579bfc857a8 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -4564,9 +4564,10 @@ class ConstraintSystem { return {type, kind, BindingSource}; } - static PotentialBinding forHole(ASTContext &ctx, + static PotentialBinding forHole(TypeVariableType *typeVar, ConstraintLocator *locator) { - return {ctx.TheUnresolvedType, AllowedBindingKind::Exact, + return {HoleType::get(typeVar->getASTContext(), typeVar), + AllowedBindingKind::Exact, /*source=*/locator}; } }; From b4d3237beab389b0686e8727dcdf185fee5636d6 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 26 Aug 2020 18:45:17 -0700 Subject: [PATCH 351/663] [CSDiagnostics] Adjust diagnostics to account that type holes in solution are `UnresolvedType` --- lib/Sema/CSDiagnostics.cpp | 4 ++-- lib/Sema/CSDiagnostics.h | 30 +++++++++++++++++------------ test/Constraints/rdar44770297.swift | 6 ++---- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index ec52d0ec612ad..25b54e13e7538 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -5057,7 +5057,7 @@ bool CollectionElementContextualFailure::diagnoseAsError() { // holes present in the contextual type. if (FailureDiagnostic::getContextualTypePurpose(getAnchor()) == ContextualTypePurpose::CTP_ForEachStmt && - contextualType->hasHole()) { + contextualType->hasUnresolvedType()) { diagnostic.emplace(emitDiagnostic( (contextualType->is() && !eltType->is()) ? diag::cannot_match_expr_tuple_pattern_with_nontuple_value @@ -6315,7 +6315,7 @@ bool UnableToInferClosureParameterType::diagnoseAsError() { if (parentExpr) { // Missing or invalid member reference in call. if (auto *AE = dyn_cast(parentExpr)) { - if (getType(AE->getFn())->isHole()) + if (getType(AE->getFn())->is()) return false; } diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index e1c925322d495..956c91736dd0e 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -94,20 +94,26 @@ class FailureDiagnostic { /// Resolve type variables present in the raw type, if any. Type resolveType(Type rawType, bool reconstituteSugar = false, bool wantRValue = true) const { - if (!rawType->hasTypeVariable()) { - if (reconstituteSugar) - rawType = rawType->reconstituteSugar(/*recursive*/ true); - return wantRValue ? rawType->getRValueType() : rawType; + auto &cs = getConstraintSystem(); + + if (rawType->hasTypeVariable() || rawType->hasHole()) { + rawType = rawType.transform([&](Type type) { + if (auto *typeVar = type->getAs()) { + auto resolvedType = S.simplifyType(typeVar); + Type GP = typeVar->getImpl().getGenericParameter(); + return resolvedType->is() && GP + ? GP + : resolvedType; + } + + return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType) + : type; + }); } - auto &cs = getConstraintSystem(); - return cs.simplifyTypeImpl(rawType, [&](TypeVariableType *typeVar) -> Type { - auto fixed = S.simplifyType(typeVar); - auto *genericParam = typeVar->getImpl().getGenericParameter(); - if (fixed->isHole() && genericParam) - return genericParam; - return resolveType(fixed, reconstituteSugar, wantRValue); - }); + if (reconstituteSugar) + rawType = rawType->reconstituteSugar(/*recursive*/ true); + return wantRValue ? rawType->getRValueType() : rawType; } template diff --git a/test/Constraints/rdar44770297.swift b/test/Constraints/rdar44770297.swift index 8d0b128b9e136..9853dd1ca2f53 100644 --- a/test/Constraints/rdar44770297.swift +++ b/test/Constraints/rdar44770297.swift @@ -4,10 +4,8 @@ protocol P { associatedtype A } -func foo(_: () throws -> T) -> T.A? { +func foo(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Never'}} fatalError() } -let _ = foo() {fatalError()} & nil // expected-error {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}} -// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} -// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} +let _ = foo() {fatalError()} & nil // expected-error {{global function 'foo' requires that 'Never' conform to 'P'}} From d287963c4d175dfdad824d2628df525f87295bea Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 26 Aug 2020 19:27:21 -0700 Subject: [PATCH 352/663] [sil-mode] Change viewcfg integration to specify dot as a renderer. --- utils/sil-mode.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/sil-mode.el b/utils/sil-mode.el index fe29c99d9b58b..59cc44ba0c4c7 100644 --- a/utils/sil-mode.el +++ b/utils/sil-mode.el @@ -259,6 +259,7 @@ ;; *NOTE* viewcfg must be in the $PATH and .dot files should be associated with ;; the graphviz app. (defvar sil-mode-viewcfg-program-name "viewcfg") +(defvar sil-mode-viewcfg-renderer "dot") (defvar sil-mode-viewcfg-buffer-name "*viewcfg*") (defcustom sil-mode-viewcfg-command-default "viewcfg" @@ -281,7 +282,8 @@ (process-connection-type nil)) (let ((p (start-process sil-mode-viewcfg-program-name sil-mode-viewcfg-buffer-name - sil-mode-viewcfg-command))) + sil-mode-viewcfg-command + (concat "--renderer=" sil-mode-viewcfg-renderer)))) (process-send-region p brace-start brace-end) (process-send-eof p))))) From 5b5e30b6d7877c58e260839c0daf878fd1506f54 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 18:01:59 -0400 Subject: [PATCH 353/663] Implement implicit member chains --- include/swift/AST/DiagnosticsSema.def | 2 + lib/Sema/CSApply.cpp | 23 +- lib/Sema/CSDiagnostics.cpp | 45 ++-- lib/Sema/CSGen.cpp | 115 ++++++--- lib/Sema/CSSimplify.cpp | 84 ++++--- lib/Sema/CSSolver.cpp | 13 ++ lib/Sema/ConstraintSystem.cpp | 1 + lib/Sema/ConstraintSystem.h | 74 ++++++ test/Constraints/construction.swift | 5 +- test/Constraints/diagnostics.swift | 2 +- test/expr/delayed-ident/member_chains.swift | 218 ++++++++++++++++++ test/expr/delayed-ident/nested_type.swift | 19 ++ test/expr/delayed-ident/static_var.swift | 3 +- .../postfix/dot/optional_context_member.swift | 5 +- 14 files changed, 509 insertions(+), 100 deletions(-) create mode 100644 test/expr/delayed-ident/member_chains.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index beaf7b6ea3dd5..5a0a494f535e6 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -112,6 +112,8 @@ ERROR(expected_argument_in_contextual_member,none, "member %0 expects argument of type %1", (DeclName, Type)) ERROR(expected_parens_in_contextual_member,none, "member %0 is a function; did you mean to call it?", (DeclName)) +ERROR(expected_parens_in_contextual_member_type,none, + "member %0 is a function that produces expected type %1; did you mean to call it?", (DeclName, Type)) ERROR(expected_result_in_contextual_member,none, "member %0 in %2 produces result of type %1, but context expects %2", diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 0add614158d91..1e1775e464dd1 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2753,17 +2753,16 @@ namespace { } Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { - // Dig out the type of the base, which will be the result type of this - // expression. If constraint solving resolved this to an UnresolvedType, + // If constraint solving resolved the base type to an UnresolvedType, // then we're in an ambiguity tolerant mode used for diagnostic // generation. Just leave this as an unresolved member reference. - Type resultTy = simplifyType(cs.getType(expr)); - if (resultTy->hasUnresolvedType()) { - cs.setType(expr, resultTy); + Type baseTy = simplifyType(solution.getUnresolvedMemberBaseType(expr)); + + if (baseTy->hasUnresolvedType()) { + cs.setType(expr, baseTy); return expr; } - Type baseTy = resultTy->getRValueType(); auto &ctx = cs.getASTContext(); // Find the selected member. @@ -2821,7 +2820,8 @@ namespace { diagnoseAmbiguousNominalMember(baseTy, result); } - return coerceToType(result, resultTy, cs.getConstraintLocator(expr)); + return coerceToType(result, simplifyType(cs.getType(expr)), + cs.getConstraintLocator(expr)); } /// Diagnose if the base type is optional, we're referring to a nominal @@ -8449,6 +8449,15 @@ void Solution::setExprTypes(Expr *expr) const { expr->walk(SET); } +Type Solution::getUnresolvedMemberBaseType(UnresolvedMemberExpr *expr) const { + auto result = unresolvedMemberBaseTypes.find(expr); + if (result != unresolvedMemberBaseTypes.end()) + return result->second; + + auto &cs = getConstraintSystem(); + return cs.getUnresolvedMemberBaseType(expr); +} + /// MARK: SolutionResult implementation. SolutionResult SolutionResult::forSolved(Solution &&solution) { diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 4bef05bd9c4eb..5c04d1aefce5a 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1200,14 +1200,6 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { auto *anchor = castToExpr(getAnchor()); - // If this is an unresolved member expr e.g. `.foo` its - // base type is going to be the same as result type minus - // r-value adjustment because base could be an l-value type. - // We want to fix both cases by only diagnose one of them, - // otherwise this is just going to result in a duplcate diagnostic. - if (getLocator()->isLastElement()) - return false; - if (auto assignExpr = dyn_cast(anchor)) anchor = assignExpr->getSrc(); @@ -2137,10 +2129,15 @@ bool ContextualFailure::diagnoseAsError() { return false; } - case ConstraintLocator::RValueAdjustment: { + case ConstraintLocator::Member: + case ConstraintLocator::FunctionResult: + case ConstraintLocator::UnresolvedMember: { auto &solution = getSolution(); - auto overload = getOverloadChoiceIfAvailable( - getConstraintLocator(anchor, ConstraintLocator::UnresolvedMember)); + auto locator = getConstraintLocator(anchor, + isExpr(anchor) + ? ConstraintLocator::UnresolvedMember + : ConstraintLocator::Member); + auto overload = getOverloadChoiceIfAvailable(locator); if (!(overload && overload->choice.isDecl())) return false; @@ -2175,13 +2172,22 @@ bool ContextualFailure::diagnoseAsError() { }); if (numMissingArgs == 0 || numMissingArgs > 1) { - auto diagnostic = emitDiagnostic( - diag::expected_parens_in_contextual_member, choice->getName()); - - // If there are no parameters we can suggest a fix-it - // to form an explicit call. - if (numMissingArgs == 0) - diagnostic.fixItInsertAfter(getSourceRange().End, "()"); + auto applyFixIt = [&](InFlightDiagnostic &diagnostic) { + // If there are no parameters we can suggest a fix-it + // to form an explicit call. + if (numMissingArgs == 0) + diagnostic.fixItInsertAfter(getSourceRange().End, "()"); + }; + if (fnType->getResult()->isEqual(toType)) { + auto diag = emitDiagnostic( + diag::expected_parens_in_contextual_member_type, + choice->getName(), fnType->getResult()); + applyFixIt(diag); + } else { + auto diag = emitDiagnostic(diag::expected_parens_in_contextual_member, + choice->getName()); + applyFixIt(diag); + } } else { emitDiagnostic(diag::expected_argument_in_contextual_member, choice->getName(), params.front().getPlainType()); @@ -2400,6 +2406,9 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const { if (getLocator()->isLastElement()) return false; + if (getLocator()->isLastElement()) + return false; + auto *srcFT = getFromType()->getAs(); if (!srcFT || !(srcFT->getParams().empty() || diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index d54105b2c721a..91f8ad9bf8b77 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -848,6 +848,35 @@ namespace { return tv; } + Type addUnresolvedMemberChainConstraints(Expr *expr, Type resultTy, + ConstraintLocator *resultLocator, + unsigned additionalOptions = 0) { + // If this is a member chain hanging off of an UnresolvedMemberExpr, + // and we're at the last element of the chain, then the contextual type + // (represented with a new type variable) must equal the base type. + if (CS.isMemberChainTail(expr)) { + auto *chainBaseExpr = CS.getMemberChainBase(expr); + if (auto *UME = dyn_cast(chainBaseExpr)) { + // Create a new type variable representing the result of the chain. + auto chainResultTy = CS.createTypeVariable(resultLocator, + additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape); + auto chainBaseTy = CS.getUnresolvedMemberBaseType(UME); + + // The result of this element of the chain must be convertible to the + // contextual type, and the contextual type must be equal to the base. + CS.addConstraint(ConstraintKind::Conversion, resultTy, chainResultTy, + resultLocator); + CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, + CS.getConstraintLocator(UME, ConstraintLocator::MemberRefBase)); + + return chainResultTy; + } + } + + // Otherwise, just use the proposed result type. + return resultTy; + } + /// Add constraints for a subscript operation. Type addSubscriptConstraints( Expr *anchor, Type baseTy, Expr *index, @@ -1431,15 +1460,17 @@ namespace { expr->getArgument() ? FunctionRefKind::DoubleApply : FunctionRefKind::Compound; - auto memberLocator - = CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember); + auto memberLocator = CS.getConstraintLocator(expr, + ConstraintLocator::UnresolvedMember); // Since base type in this case is completely dependent on context it // should be marked as a potential hole. - auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape | - TVO_CanBindToHole); - auto memberTy = CS.createTypeVariable( - memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); + auto baseTy = CS.createTypeVariable(baseLocator, + TVO_CanBindToHole | TVO_CanBindToNoEscape); + CS.setUnresolvedMemberBaseType(expr, baseTy); + + auto memberTy = CS.createTypeVariable(memberLocator, + TVO_CanBindToLValue | TVO_CanBindToNoEscape); // An unresolved member expression '.member' is modeled as a value member // constraint @@ -1455,14 +1486,11 @@ namespace { // If there is an argument, apply it. if (auto arg = expr->getArgument()) { - // The result type of the function must be convertible to the base type. - // TODO: we definitely want this to include ImplicitlyUnwrappedOptional; - // does it need to include everything else in the world? - auto outputTy = CS.createTypeVariable( - CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), - TVO_CanBindToNoEscape); - CS.addConstraint(ConstraintKind::Conversion, outputTy, baseTy, - CS.getConstraintLocator(expr, ConstraintLocator::RValueAdjustment)); + // Create a new type variable for the result of the function. + auto outputLocator = CS.getConstraintLocator(expr, + ConstraintLocator::FunctionResult); + auto outputTy = CS.createTypeVariable(outputLocator, + TVO_CanBindToNoEscape); // The function/enum case must be callable with the given argument. @@ -1481,23 +1509,14 @@ namespace { CS.getConstraintLocator(expr), {expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()}); - return baseTy; + return addUnresolvedMemberChainConstraints(expr, outputTy, + outputLocator); } - - // Otherwise, the member needs to be convertible to the base type. - CS.addConstraint(ConstraintKind::Conversion, memberTy, baseTy, - CS.getConstraintLocator(expr, ConstraintLocator::RValueAdjustment)); - // The member type also needs to be convertible to the context type, which - // preserves lvalue-ness. - auto resultTy = CS.createTypeVariable(memberLocator, - TVO_CanBindToLValue | - TVO_CanBindToNoEscape); - CS.addConstraint(ConstraintKind::Conversion, memberTy, resultTy, - memberLocator); - CS.addConstraint(ConstraintKind::Equal, resultTy, baseTy, - memberLocator); - return resultTy; + // Otherwise, add the usual constraints for an element of an unresolved + // member chain. + return addUnresolvedMemberChainConstraints(expr, memberTy, memberLocator, + TVO_CanBindToLValue); } Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { @@ -1561,9 +1580,14 @@ namespace { return methodTy; } - return addMemberRefConstraints(expr, expr->getBase(), expr->getName(), - expr->getFunctionRefKind(), - expr->getOuterAlternatives()); + auto resultTy = addMemberRefConstraints(expr, expr->getBase(), + expr->getName(), + expr->getFunctionRefKind(), + expr->getOuterAlternatives()); + + return addUnresolvedMemberChainConstraints(expr, resultTy, + CS.getConstraintLocator(expr, ConstraintLocator::Member), + TVO_CanBindToLValue); } Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) { @@ -1722,10 +1746,15 @@ namespace { if (!isValidBaseOfMemberRef(base, diag::cannot_subscript_nil_literal)) return nullptr; - return addSubscriptConstraints(expr, CS.getType(base), - expr->getIndex(), - decl, expr->getArgumentLabels(), - expr->getUnlabeledTrailingClosureIndex()); + auto resultTy = addSubscriptConstraints(expr, CS.getType(base), + expr->getIndex(), + decl, expr->getArgumentLabels(), + expr->getUnlabeledTrailingClosureIndex()); + auto resultLocator = CS.getConstraintLocator(expr, + ConstraintLocator::FunctionResult); + + return addUnresolvedMemberChainConstraints(expr, resultTy, resultLocator, + TVO_CanBindToLValue); } Type visitArrayExpr(ArrayExpr *expr) { @@ -2908,6 +2937,15 @@ namespace { resultType = fixedType; } + // If the ApplyExpr is a CallExpr, add chain constraints as necessary. + if (isa(expr)) { + auto resultLocator = CS.getConstraintLocator(expr, + ConstraintLocator::FunctionResult); + + return addUnresolvedMemberChainConstraints(expr, resultType, + resultLocator); + } + return resultType; } @@ -3218,7 +3256,8 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return objectTy; + return addUnresolvedMemberChainConstraints(expr, objectTy, locator, + TVO_CanBindToLValue); } Type visitOptionalEvaluationExpr(OptionalEvaluationExpr *expr) { @@ -3253,7 +3292,7 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return objectTy; + return addUnresolvedMemberChainConstraints(expr, objectTy, locator); } Type visitOpenExistentialExpr(OpenExistentialExpr *expr) { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 5ba9345c7c555..274fc1055697d 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4135,6 +4135,20 @@ bool ConstraintSystem::repairFailures( } case ConstraintLocator::FunctionResult: { + // FIXME: Is this necessary? + if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, + locator)) + break; + + // If this mismatch occurs at the tail of an unresolved member chain, + // there's a contextual mismatch. + if (isUnresolvedMemberChainTail(anchor)) { + auto *fix = IgnoreContextualType::create(*this, lhs, rhs, + getConstraintLocator(locator)); + conversionsOrFixes.push_back(fix); + break; + } + auto *loc = getConstraintLocator(anchor, {path.begin(), path.end() - 1}); // If this is a mismatch between contextual type and (trailing) // closure with explicitly specified result type let's record it @@ -4181,6 +4195,16 @@ bool ConstraintSystem::repairFailures( repairByInsertingExplicitCall(lhs, rhs)) return true; } + + // If this mismatch occurs at the tail of an unresolved member chain, + // there's a contextual mismatch. + if (isUnresolvedMemberChainTail(anchor)) { + auto *fix = IgnoreContextualType::create(*this, lhs, rhs, + getConstraintLocator(locator)); + conversionsOrFixes.push_back(fix); + break; + } + break; } @@ -4306,12 +4330,7 @@ bool ConstraintSystem::repairFailures( break; } - // Unresolved member type mismatches are handled when - // r-value adjustment constraint fails. - case ConstraintLocator::UnresolvedMember: - return true; - - case ConstraintLocator::RValueAdjustment: { + case ConstraintLocator::UnresolvedMember: { if (!isExpr(anchor)) break; @@ -4319,9 +4338,7 @@ bool ConstraintSystem::repairFailures( locator)) break; - // r-value adjustment is used to connect base type of - // unresolved member to its output type, if there is - // a type mismatch here it's contextual e.g. + // If there is a type mismatch here it's contextual e.g., // `let x: E = .foo(42)`, where `.foo` is a member of `E` // but produces an incorrect type. auto *fix = IgnoreContextualType::create(*this, lhs, rhs, @@ -6779,27 +6796,32 @@ static ConstraintFix *validateInitializerRef(ConstraintSystem &cs, } } // Initializer reference which requires contextual base type e.g. - // `.init(...)`. + // `.init(...)`. Could also be a nested type or typealias being constructed + // via implicit member syntax, e.g., `let _: Base = .Nested()` where + // `Base.Nested: Base`. } else if (auto *UME = getAsExpr(anchor)) { - // We need to find type variable which represents contextual base. - auto *baseLocator = cs.getConstraintLocator( - UME, locatorEndsWith(locator, ConstraintLocator::ConstructorMember) - ? ConstraintLocator::UnresolvedMember - : ConstraintLocator::MemberRefBase); - - // FIXME: Type variables responsible for contextual base could be cached - // in the constraint system to speed up lookup. - auto result = llvm::find_if( - cs.getTypeVariables(), [&baseLocator](const TypeVariableType *typeVar) { - return typeVar->getImpl().getLocator() == baseLocator; - }); + // If we're accessing a nested type to perform the construction implicitly, + // then the type we're constructing may not actually be the base of the + // UnresolvedMemberExpr--instead, it will be the type of the nested type + // member. + if (locatorEndsWith(locator, ConstraintLocator::ConstructorMember)) { + auto *baseLocator = cs.getConstraintLocator(UME, + ConstraintLocator::UnresolvedMember); + auto result = llvm::find_if( + cs.getTypeVariables(), [&baseLocator](const TypeVariableType *typeVar) { + return typeVar->getImpl().getLocator() == baseLocator; + }); + assert(result != cs.getTypeVariables().end()); + baseType = cs.simplifyType(*result); - assert(result != cs.getTypeVariables().end()); - baseType = cs.simplifyType(*result)->getRValueType(); - // Constraint for member base is formed as '$T.Type[.(anchor)) { // Key path can't refer to initializers e.g. `\Type.init` return AllowInvalidRefInKeyPath::forRef(cs, init, locator); @@ -10061,6 +10083,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( impact = 10; } + if (locator->isLastElement()) { + // If this is a contextual failure for an unresolved member, then increase + // the impact to attempt other fixes first and avoid ambiguity. + impact = 5; + } + if (recordFix(fix, impact)) return SolutionKind::Error; diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 8f0afc7b18b81..ba10f3c128c73 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -176,6 +176,10 @@ Solution ConstraintSystem::finalize() { solution.nodeTypes.insert(nodeType); } + for (auto &baseType : UnresolvedMemberBaseTypes) { + solution.unresolvedMemberBaseTypes.insert(baseType); + } + // Remember contextual types. solution.contextualTypes.assign( contextualTypes.begin(), contextualTypes.end()); @@ -251,6 +255,11 @@ void ConstraintSystem::applySolution(const Solution &solution) { setType(nodeType.first, nodeType.second); } + // Add the unresolved member base types back. + for (auto &baseType : solution.unresolvedMemberBaseTypes) { + setUnresolvedMemberBaseType(baseType.first, baseType.second); + } + // Add the contextual types. for (const auto &contextualType : solution.contextualTypes) { if (!getContextualTypeInfo(contextualType.first)) { @@ -475,6 +484,7 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs) numOpenedExistentialTypes = cs.OpenedExistentialTypes.size(); numDefaultedConstraints = cs.DefaultedConstraints.size(); numAddedNodeTypes = cs.addedNodeTypes.size(); + numUnresolvedMemberBaseTypes = cs.UnresolvedMemberBaseTypes.size(); numCheckedConformances = cs.CheckedConformances.size(); numDisabledConstraints = cs.solverState->getNumDisabledConstraints(); numFavoredConstraints = cs.solverState->getNumFavoredConstraints(); @@ -553,6 +563,9 @@ ConstraintSystem::SolverScope::~SolverScope() { } truncate(cs.addedNodeTypes, numAddedNodeTypes); + // Remove any unresolved member base types. + truncate(cs.UnresolvedMemberBaseTypes, numUnresolvedMemberBaseTypes); + // Remove any conformances checked along the current path. truncate(cs.CheckedConformances, numCheckedConformances); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 1214740c8d1d5..0f518e4695ab8 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3679,6 +3679,7 @@ void constraints::simplifyLocator(ASTNode &anchor, } case ConstraintLocator::ApplyFunction: + case ConstraintLocator::FunctionResult: // Extract application function. if (auto applyExpr = getAsExpr(anchor)) { anchor = applyExpr->getFn(); diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index bc95ed45c0b55..cb2f16f26696b 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1080,6 +1080,9 @@ class Solution { /// The node -> type mappings introduced by this solution. llvm::DenseMap nodeTypes; + /// The unresolved member base types introduced by this solution. + llvm::MapVector unresolvedMemberBaseTypes; + /// Contextual types introduced by this solution. std::vector> contextualTypes; @@ -1195,6 +1198,9 @@ class Solution { /// "resolved" concrete type. Type getResolvedType(ASTNode node) const; + /// Retrieve the type of a particular \c UnresolvedMemberExpr's base. + Type getUnresolvedMemberBaseType(UnresolvedMemberExpr *expr) const; + /// Resolve type variables present in the raw type, using generic parameter /// types where possible. Type resolveInterfaceType(Type type) const; @@ -2050,6 +2056,9 @@ class ConstraintSystem { llvm::DenseMap OpenedParameterTypes; + /// Maps \c UnresolvedMemberExprs to their (implicit) base types. + llvm::MapVector UnresolvedMemberBaseTypes; + /// The set of constraint restrictions used to reach the /// current constraint system. /// @@ -2571,6 +2580,8 @@ class ConstraintSystem { unsigned numAddedNodeTypes; + unsigned numUnresolvedMemberBaseTypes; + unsigned numCheckedConformances; unsigned numDisabledConstraints; @@ -2873,6 +2884,17 @@ class ConstraintSystem { return CTP_Unused; } + void setUnresolvedMemberBaseType(UnresolvedMemberExpr *expr, Type type) { + assert(expr && "Expected non-null expression"); + assert(type && "Expected non-null type"); + UnresolvedMemberBaseTypes[expr] = type; + } + + Type getUnresolvedMemberBaseType(UnresolvedMemberExpr *expr) { + assert(expr && "Expected non-null expression"); + return UnresolvedMemberBaseTypes.find(expr)->second; + } + void setSolutionApplicationTarget( SolutionApplicationTargetsKey key, SolutionApplicationTarget target) { assert(solutionApplicationTargets.count(key) == 0 && @@ -3022,6 +3044,58 @@ class ConstraintSystem { bool isDeclUnavailable(const Decl *D, ConstraintLocator *locator = nullptr) const; + /// Find the next element in a chain of members. If this expression is (or + /// could be) the base of such a chain, this will return \c nullptr. + Expr *getMemberChainSubExpr(Expr *expr) { + assert(expr && "isMemberChainSubExpr called with null expr!"); + if (auto *UDE = dyn_cast(expr)) { + return UDE->getBase(); + } else if (auto *CE = dyn_cast(expr)) { + return CE->getFn(); + } else if (auto *BOE = dyn_cast(expr)) { + return BOE->getSubExpr(); + } else if (auto *FVE = dyn_cast(expr)) { + return FVE->getSubExpr(); + } else if (auto *SE = dyn_cast(expr)) { + return SE->getBase(); + } else { + return nullptr; + } + } + + /// Returns the base of a chain of member accesses/method calls. Most + /// expressions do not participate in member chains, and just return \c this. + Expr *getMemberChainBase(Expr *expr) { + if (auto *subExpr = getMemberChainSubExpr(expr)) + return getMemberChainBase(subExpr); + else + return expr; + } + + /// Whether this expression is a member of a member chain. + bool isMemberChainMember(Expr *expr) { + return getMemberChainSubExpr(expr) != nullptr; + } + /// Whether this expression sits at the end of a chain of member accesses. + bool isMemberChainTail(Expr *expr) { + assert(expr && "isMemberChainTail called with null expr!"); + // If this expression's parent is not itself part of a chain (or, this expr + // has no parent expr), this must be the tail of the chain. + Expr *parent = getParentExpr(expr); + + return parent == nullptr || !isMemberChainMember(parent); + } + + /// Whether this node sits at the end of a member chain that hangs off an + /// \c UnresolvedMemberExpr at the base. + bool isUnresolvedMemberChainTail(ASTNode node) { + if (auto *expr = getAsExpr(node)) + return isMemberChainTail(expr) + && isa(getMemberChainBase(expr)); + else + return false; + } + public: /// Whether we should attempt to fix problems. diff --git a/test/Constraints/construction.swift b/test/Constraints/construction.swift index 82f660ed6a7bb..048667c4e129b 100644 --- a/test/Constraints/construction.swift +++ b/test/Constraints/construction.swift @@ -22,7 +22,7 @@ enum Z { init(_ x: Int, _ y: Int) { self = .point(x, y) } } -enum Optional { // expected-note {{'T' declared as parameter to type 'Optional'}} +enum Optional { case none case value(T) @@ -59,8 +59,7 @@ acceptString("\(hello), \(world) #\(i)!") Optional(1) // expected-warning{{unused}} Optional(1) // expected-warning{{unused}} _ = .none as Optional -Optional(.none) // expected-error{{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{9-9=}} -// expected-error@-1 {{cannot infer contextual base in reference to member 'none'}} +Optional(.none) // expected-error {{cannot infer contextual base in reference to member 'none'}} // Interpolation _ = "\(hello), \(world) #\(i)!" diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bff33fe7caa73..fac6d8b343a10 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -423,7 +423,7 @@ let _ : Color = .rainbow(42) // expected-error {{argument passed to call that t let _ : (Int, Float) = (42.0, 12) // expected-error {{cannot convert value of type '(Double, Float)' to specified type '(Int, Float)'}} -let _ : Color = .rainbow // expected-error {{member 'rainbow()' is a function; did you mean to call it?}} {{25-25=()}} +let _ : Color = .rainbow // expected-error {{member 'rainbow()' is a function that produces expected type 'Color'; did you mean to call it?}} {{25-25=()}} let _: Color = .overload(a : 1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} let _: Color = .overload(1.0) // expected-error {{no exact matches in call to static method 'overload'}} diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift new file mode 100644 index 0000000000000..c8f468ace2e9f --- /dev/null +++ b/test/expr/delayed-ident/member_chains.swift @@ -0,0 +1,218 @@ +// RUN: %target-typecheck-verify-swift -swift-version 5 + +struct ImplicitMembers: Equatable { + struct Other { + var implicit: ImplicitMembers { ImplicitMembers() } + } + + static var other = Other() + static func createOther() -> Other { + Other() + } + var anotherOther: Other { Other() } + func getAnotherOther() -> Other { + Other() + } + + static var implicit = ImplicitMembers() + static func createImplicit() -> ImplicitMembers { + ImplicitMembers() + } + + static var optional: ImplicitMembers? = ImplicitMembers() + static func createOptional() -> ImplicitMembers? { + ImplicitMembers() + } + static var superOptional: ImplicitMembers??? = ImplicitMembers() + + var another: ImplicitMembers { ImplicitMembers() } + + func getAnother() -> ImplicitMembers { + ImplicitMembers() + } + + func getAnother(arg: Int) -> ImplicitMembers { + ImplicitMembers() + } + + var anotherOptional: ImplicitMembers? { ImplicitMembers() } + + func getAnotherOptional() -> ImplicitMembers? { + ImplicitMembers() + } + + func getAnotherOptional(arg: Int) -> ImplicitMembers? { + ImplicitMembers() + } + + subscript(arg: Void) -> ImplicitMembers { ImplicitMembers() } + subscript(optional arg: Void) -> ImplicitMembers? { ImplicitMembers() } + subscript(func arg: Void) -> (() -> ImplicitMembers) { { ImplicitMembers() } } + subscript(funcOptional arg: Void) -> (() -> ImplicitMembers?) { { ImplicitMembers() } } + subscript(optionalFunc arg: Void) -> (() -> ImplicitMembers)? { { ImplicitMembers() } } +} + +let _: ImplicitMembers = .implicit +let _: ImplicitMembers? = .implicit +let _: ImplicitMembers? = .optional + +let _: ImplicitMembers = .implicit.another.another +let _: ImplicitMembers = .createImplicit().another.another +let _: ImplicitMembers = .init().another.another + +let _: ImplicitMembers = .implicit.getAnother().another +let _: ImplicitMembers = .createImplicit().getAnother().another +let _: ImplicitMembers = .init().getAnother().another + +let _: ImplicitMembers = .implicit.getAnother(arg: 0).another +let _: ImplicitMembers = .createImplicit().getAnother(arg: 0).another +let _: ImplicitMembers = .init().getAnother(arg: 0).another + +let _: ImplicitMembers = .implicit.another.getAnother() +let _: ImplicitMembers = .createImplicit().another.getAnother() +let _: ImplicitMembers = .init().another.getAnother() + +let _: ImplicitMembers = .implicit.another.getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().another.getAnother(arg: 0) +let _: ImplicitMembers = .init().another.getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .init().getAnother().getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.getAnother().getAnother(arg: 0).another +let _: ImplicitMembers = .createImplicit().getAnother().getAnother(arg: 0).another +let _: ImplicitMembers = .init().getAnother().getAnother(arg: 0).another + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.another.another.another.another.another +let _: ImplicitMembers = .implicit.getAnother().getAnother().getAnother().getAnother().getAnother() +let _: ImplicitMembers = .implicit.getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0) + +let _: ImplicitMembers = .optional! +let _: ImplicitMembers = .optional!.another +let _: ImplicitMembers = .createOptional()!.another +let _: ImplicitMembers = .optional!.anotherOptional! +let _: ImplicitMembers = .createOptional()!.anotherOptional! +let _: ImplicitMembers = .optional!.getAnotherOptional()! +let _: ImplicitMembers = .createOptional()!.getAnotherOptional()! + +let _: ImplicitMembers = .other.implicit +let _: ImplicitMembers = .implicit.anotherOther.implicit +let _: ImplicitMembers = .createOther().implicit +let _: ImplicitMembers = .implicit.getAnotherOther().implicit + +let _: ImplicitMembers = .other // expected-error {{member 'other' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther // expected-error {{member 'implicit' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod() // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember.another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod().another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} +let _: ImplicitMembers = .implicit.getAnotherOther() // expected-error {{member 'getAnotherOther()' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} + +let _: ImplicitMembers? = .implicit.another +let _: ImplicitMembers? = .implicit.anotherOptional + +let _: ImplicitMembers? = .optional +let _: ImplicitMembers? = .optional?.another +let _: ImplicitMembers? = .optional?.anotherOptional +let _: ImplicitMembers? = .optional?.getAnother() +let _: ImplicitMembers? = .optional?.getAnotherOptional() +let _: ImplicitMembers? = .optional?.anotherOptional?.another +let _: ImplicitMembers? = .optional?.getAnotherOptional()?.another +let _: ImplicitMembers? = .createOptional() +let _: ImplicitMembers? = .createOptional()?.another +let _: ImplicitMembers? = .createOptional()?.anotherOptional +let _: ImplicitMembers? = .createOptional()?.getAnother() +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional() +let _: ImplicitMembers? = .createOptional()?.anotherOptional?.another +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.another +// FIXME: This should be allowed +// let _: ImplicitMembers? = .superOptional???.another + +let _: ImplicitMembers = .implicit[()] +let _: ImplicitMembers = .implicit[optional: ()]! +let _: ImplicitMembers? = .implicit[optional: ()] +let _: ImplicitMembers = .implicit[func: ()]() +let _: ImplicitMembers = .implicit[funcOptional: ()]()! +let _: ImplicitMembers? = .implicit[funcOptional: ()]() +let _: ImplicitMembers = .implicit[optionalFunc: ()]!() +let _: ImplicitMembers? = .implicit[optionalFunc: ()]?() +let _: ImplicitMembers = .implicit.another[()] +let _: ImplicitMembers = .implicit.another[optional: ()]! +let _: ImplicitMembers? = .implicit.another[optional: ()] +let _: ImplicitMembers = .implicit.another[func: ()]() +let _: ImplicitMembers = .implicit.another[funcOptional: ()]()! +let _: ImplicitMembers? = .implicit.another[funcOptional: ()]() +let _: ImplicitMembers = .implicit.another[optionalFunc: ()]!() +let _: ImplicitMembers? = .implicit.another[optionalFunc: ()]?() +let _: ImplicitMembers = .implicit[()].another +let _: ImplicitMembers = .implicit[optional: ()]!.another +let _: ImplicitMembers? = .implicit[optional: ()]?.another +let _: ImplicitMembers = .implicit[func: ()]().another +let _: ImplicitMembers = .implicit[funcOptional: ()]()!.another +let _: ImplicitMembers? = .implicit[funcOptional: ()]()?.another +let _: ImplicitMembers = .implicit[optionalFunc: ()]!().another +let _: ImplicitMembers? = .implicit[optionalFunc: ()]?().another + +func implicit(_ i: inout ImplicitMembers) { + if i == .implicit {} + if i == .implicit.another {} + if i == .implicit.getAnother() {} + if i == .optional?.another {} + if i == .optional!.another {} + if i == .createOptional()?.another {} +} + +struct ImplicitGeneric { + static var implicit: ImplicitGeneric { ImplicitGeneric() } + var another: ImplicitGeneric { ImplicitGeneric() } + func getAnother() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +extension ImplicitGeneric where T == Int { + static var implicitInt: ImplicitGeneric { ImplicitGeneric() } + static var implicitString: ImplicitGeneric { ImplicitGeneric() } + var anotherInt: ImplicitGeneric { ImplicitGeneric() } + var anotherIntString: ImplicitGeneric { ImplicitGeneric() } + func getAnotherInt() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +extension ImplicitGeneric where T == String { + static var implicitString: ImplicitGeneric { ImplicitGeneric() } + var anotherString: ImplicitGeneric { ImplicitGeneric() } + var anotherStringInt: ImplicitGeneric { ImplicitGeneric() } + func getAnotherString() -> ImplicitGeneric { + ImplicitGeneric() + } + func getAnotherStringInt() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +func implicit(_ arg: ImplicitGeneric) {} + +implicit(.implicitInt) +implicit(.implicit.anotherInt) +implicit(.implicit.anotherInt.another) +implicit(.implicit.another.anotherInt) +implicit(.implicit.getAnotherInt()) +implicit(.implicit.another.getAnotherInt()) +implicit(.implicit.getAnother().anotherInt) +implicit(.implicit.getAnotherInt()) +implicit(.implicit.getAnother().getAnotherInt()) +implicit(.implicitString.anotherStringInt) +// Member types along the chain can have different generic arguments +implicit(.implicit.anotherIntString.anotherStringInt) + +implicit(.implicit.anotherString.anotherStringInt) // expected-error {{type of expression is ambiguous without more context}} +implicit(.implicit.getAnotherString().anotherStringInt) // expected-error {{type of expression is ambiguous without more context}} +implicit(.implicit.anotherString.getAnotherStringInt()) // expected-error {{type of expression is ambiguous without more context}} +implicit(.implicit.getAnotherString().getAnotherStringInt()) // expected-error {{type of expression is ambiguous without more context}} diff --git a/test/expr/delayed-ident/nested_type.swift b/test/expr/delayed-ident/nested_type.swift index da8a3fece6538..520d08c90dea9 100644 --- a/test/expr/delayed-ident/nested_type.swift +++ b/test/expr/delayed-ident/nested_type.swift @@ -4,12 +4,21 @@ class Base { class Derived : Base { init(x: Int) {} + class Sub: Derived { + init(y: Int) {} + } + typealias Ident = Derived + typealias Ident2 = Base } typealias Ident = Base } let _: Base = .Derived(x: 12) let _: Base = .Ident() +let _: Base = .Derived.Sub(y: 1) +let _: Base = .Derived.init(x: 3) +let _: Base = .Derived.Ident(x: 3) +let _: Base = .Derived.Ident2() // Typealias in protocol. protocol P { @@ -19,9 +28,19 @@ extension P { typealias Impl2 = ConcreteP } struct ConcreteP : P { + struct NestedP: P {} + typealias Same = ConcreteP } let _: P = .Impl1() let _: P = .Impl2() let _: ConcreteP = .Impl1() let _: ConcreteP = .Impl2() +let _: P = .Impl1.NestedP() +let _: P = .Impl2.NestedP() +let _: ConcreteP = .Impl1.Same() +let _: ConcreteP = .Impl2.Same() +let _: P = .Impl1.init() +let _: P = .Impl2.init() +let _: ConcreteP = .Impl1.init() +let _: ConcreteP = .Impl2.init() diff --git a/test/expr/delayed-ident/static_var.swift b/test/expr/delayed-ident/static_var.swift index cfe701754f791..3a01e7ff4137c 100644 --- a/test/expr/delayed-ident/static_var.swift +++ b/test/expr/delayed-ident/static_var.swift @@ -50,8 +50,7 @@ var _: HasClosure = .factoryOpt(3) // expected-error@-1 {{value of optional type '((Int) -> HasClosure)?' must be unwrapped to a value of type '(Int) -> HasClosure'}} // expected-note@-2 {{coalesce}} // expected-note@-3 {{force-unwrap}} -// FIXME: we should accept this -var _: HasClosure = .factoryOpt!(4) // expected-error {{cannot infer contextual base in reference to member 'factoryOpt'}} +var _: HasClosure = .factoryOpt!(4) infix operator =%: ComparisonPrecedence diff --git a/test/expr/postfix/dot/optional_context_member.swift b/test/expr/postfix/dot/optional_context_member.swift index b761c21657ab6..c3279781e40b0 100644 --- a/test/expr/postfix/dot/optional_context_member.swift +++ b/test/expr/postfix/dot/optional_context_member.swift @@ -27,9 +27,8 @@ func nonOptContext() -> Foo { // expected-error@-1 {{value of optional type 'Foo?' must be unwrapped to a value of type 'Foo'}} // expected-note@-2 {{coalesce}} // expected-note@-3 {{force-unwrap}} - // TODO - //case (): - // return .someOptFunc()! + case (): // expected-warning {{case is already handled by previous patterns; consider removing it}} + return .someOptFunc()! } } From 1069fe280fcfb252d08111b4483537a8b4f7a89f Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 18:02:05 -0400 Subject: [PATCH 354/663] Fixup diagnostics --- lib/Sema/CSDiagnostics.cpp | 20 ++++++----- lib/Sema/CSGen.cpp | 37 ++++++++------------- lib/Sema/CSSimplify.cpp | 29 +--------------- lib/Sema/ConstraintLocator.cpp | 5 +++ lib/Sema/ConstraintLocatorPathElts.def | 3 ++ lib/Sema/ConstraintSystem.cpp | 5 +++ lib/Sema/ConstraintSystem.h | 10 ------ test/expr/delayed-ident/member_chains.swift | 17 +++++++++- 8 files changed, 56 insertions(+), 70 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 5c04d1aefce5a..5ea518d6a6281 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2129,15 +2129,19 @@ bool ContextualFailure::diagnoseAsError() { return false; } - case ConstraintLocator::Member: - case ConstraintLocator::FunctionResult: - case ConstraintLocator::UnresolvedMember: { + case ConstraintLocator::UnresolvedMemberChainResult: { auto &solution = getSolution(); - auto locator = getConstraintLocator(anchor, - isExpr(anchor) - ? ConstraintLocator::UnresolvedMember - : ConstraintLocator::Member); - auto overload = getOverloadChoiceIfAvailable(locator); + auto member = anchor; + if (auto *CE = getAsExpr(anchor)) + member = CE->getFn(); + + auto kind = ConstraintLocator::Member; + if (isExpr(anchor)) + kind = ConstraintLocator::UnresolvedMember; + else if (isExpr(anchor)) + kind = ConstraintLocator::SubscriptMember; + auto overload = getOverloadChoiceIfAvailable(getConstraintLocator(member, + kind)); if (!(overload && overload->choice.isDecl())) return false; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 91f8ad9bf8b77..cfe2e2bc2c2d7 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -849,7 +849,6 @@ namespace { } Type addUnresolvedMemberChainConstraints(Expr *expr, Type resultTy, - ConstraintLocator *resultLocator, unsigned additionalOptions = 0) { // If this is a member chain hanging off of an UnresolvedMemberExpr, // and we're at the last element of the chain, then the contextual type @@ -858,14 +857,16 @@ namespace { auto *chainBaseExpr = CS.getMemberChainBase(expr); if (auto *UME = dyn_cast(chainBaseExpr)) { // Create a new type variable representing the result of the chain. - auto chainResultTy = CS.createTypeVariable(resultLocator, + auto locator = CS.getConstraintLocator(expr, + ConstraintLocator::UnresolvedMemberChainResult); + auto chainResultTy = CS.createTypeVariable(locator, additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape); auto chainBaseTy = CS.getUnresolvedMemberBaseType(UME); // The result of this element of the chain must be convertible to the // contextual type, and the contextual type must be equal to the base. CS.addConstraint(ConstraintKind::Conversion, resultTy, chainResultTy, - resultLocator); + locator); CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, CS.getConstraintLocator(UME, ConstraintLocator::MemberRefBase)); @@ -1487,10 +1488,9 @@ namespace { // If there is an argument, apply it. if (auto arg = expr->getArgument()) { // Create a new type variable for the result of the function. - auto outputLocator = CS.getConstraintLocator(expr, - ConstraintLocator::FunctionResult); - auto outputTy = CS.createTypeVariable(outputLocator, - TVO_CanBindToNoEscape); + auto outputTy = CS.createTypeVariable( + CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), + TVO_CanBindToNoEscape); // The function/enum case must be callable with the given argument. @@ -1509,13 +1509,12 @@ namespace { CS.getConstraintLocator(expr), {expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()}); - return addUnresolvedMemberChainConstraints(expr, outputTy, - outputLocator); + return addUnresolvedMemberChainConstraints(expr, outputTy); } // Otherwise, add the usual constraints for an element of an unresolved // member chain. - return addUnresolvedMemberChainConstraints(expr, memberTy, memberLocator, + return addUnresolvedMemberChainConstraints(expr, memberTy, TVO_CanBindToLValue); } @@ -1586,7 +1585,6 @@ namespace { expr->getOuterAlternatives()); return addUnresolvedMemberChainConstraints(expr, resultTy, - CS.getConstraintLocator(expr, ConstraintLocator::Member), TVO_CanBindToLValue); } @@ -1750,10 +1748,8 @@ namespace { expr->getIndex(), decl, expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()); - auto resultLocator = CS.getConstraintLocator(expr, - ConstraintLocator::FunctionResult); - return addUnresolvedMemberChainConstraints(expr, resultTy, resultLocator, + return addUnresolvedMemberChainConstraints(expr, resultTy, TVO_CanBindToLValue); } @@ -2938,13 +2934,8 @@ namespace { } // If the ApplyExpr is a CallExpr, add chain constraints as necessary. - if (isa(expr)) { - auto resultLocator = CS.getConstraintLocator(expr, - ConstraintLocator::FunctionResult); - - return addUnresolvedMemberChainConstraints(expr, resultType, - resultLocator); - } + if (isa(expr)) + return addUnresolvedMemberChainConstraints(expr, resultType); return resultType; } @@ -3256,7 +3247,7 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return addUnresolvedMemberChainConstraints(expr, objectTy, locator, + return addUnresolvedMemberChainConstraints(expr, objectTy, TVO_CanBindToLValue); } @@ -3292,7 +3283,7 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return addUnresolvedMemberChainConstraints(expr, objectTy, locator); + return addUnresolvedMemberChainConstraints(expr, objectTy); } Type visitOpenExistentialExpr(OpenExistentialExpr *expr) { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 274fc1055697d..7a3ce7d18ee8f 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4135,20 +4135,6 @@ bool ConstraintSystem::repairFailures( } case ConstraintLocator::FunctionResult: { - // FIXME: Is this necessary? - if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, - locator)) - break; - - // If this mismatch occurs at the tail of an unresolved member chain, - // there's a contextual mismatch. - if (isUnresolvedMemberChainTail(anchor)) { - auto *fix = IgnoreContextualType::create(*this, lhs, rhs, - getConstraintLocator(locator)); - conversionsOrFixes.push_back(fix); - break; - } - auto *loc = getConstraintLocator(anchor, {path.begin(), path.end() - 1}); // If this is a mismatch between contextual type and (trailing) // closure with explicitly specified result type let's record it @@ -4195,16 +4181,6 @@ bool ConstraintSystem::repairFailures( repairByInsertingExplicitCall(lhs, rhs)) return true; } - - // If this mismatch occurs at the tail of an unresolved member chain, - // there's a contextual mismatch. - if (isUnresolvedMemberChainTail(anchor)) { - auto *fix = IgnoreContextualType::create(*this, lhs, rhs, - getConstraintLocator(locator)); - conversionsOrFixes.push_back(fix); - break; - } - break; } @@ -4330,10 +4306,7 @@ bool ConstraintSystem::repairFailures( break; } - case ConstraintLocator::UnresolvedMember: { - if (!isExpr(anchor)) - break; - + case ConstraintLocator::UnresolvedMemberChainResult: { if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, locator)) break; diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index c5b4a864e4e05..708d90d7dc6de 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -81,6 +81,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const { case ConstraintLocator::TernaryBranch: case ConstraintLocator::PatternMatch: case ConstraintLocator::ArgumentAttribute: + case ConstraintLocator::UnresolvedMemberChainResult: return 0; case ConstraintLocator::FunctionArgument: @@ -483,6 +484,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const { break; } + + case UnresolvedMemberChainResult: + out << "unresolved chain result"; + break; } } out << ']'; diff --git a/lib/Sema/ConstraintLocatorPathElts.def b/lib/Sema/ConstraintLocatorPathElts.def index 67228bcbc5591..435d20b74ec9f 100644 --- a/lib/Sema/ConstraintLocatorPathElts.def +++ b/lib/Sema/ConstraintLocatorPathElts.def @@ -192,6 +192,9 @@ CUSTOM_LOCATOR_PATH_ELT(PatternMatch) /// of a problem. CUSTOM_LOCATOR_PATH_ELT(ArgumentAttribute) +/// The result of a chain of member accesses off an UnresolvedMemberExpr +SIMPLE_LOCATOR_PATH_ELT(UnresolvedMemberChainResult) + #undef LOCATOR_PATH_ELT #undef CUSTOM_LOCATOR_PATH_ELT #undef SIMPLE_LOCATOR_PATH_ELT diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 0f518e4695ab8..322dc620c19de 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3859,6 +3859,11 @@ void constraints::simplifyLocator(ASTNode &anchor, break; } + case ConstraintLocator::UnresolvedMemberChainResult: { + path = path.slice(1); + continue; + } + default: // FIXME: Lots of other cases to handle. break; diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index cb2f16f26696b..a9018f1a302e9 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3086,16 +3086,6 @@ class ConstraintSystem { return parent == nullptr || !isMemberChainMember(parent); } - /// Whether this node sits at the end of a member chain that hangs off an - /// \c UnresolvedMemberExpr at the base. - bool isUnresolvedMemberChainTail(ASTNode node) { - if (auto *expr = getAsExpr(node)) - return isMemberChainTail(expr) - && isa(getMemberChainBase(expr)); - else - return false; - } - public: /// Whether we should attempt to fix problems. diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index c8f468ace2e9f..9333047a27f12 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -50,6 +50,7 @@ struct ImplicitMembers: Equatable { subscript(func arg: Void) -> (() -> ImplicitMembers) { { ImplicitMembers() } } subscript(funcOptional arg: Void) -> (() -> ImplicitMembers?) { { ImplicitMembers() } } subscript(optionalFunc arg: Void) -> (() -> ImplicitMembers)? { { ImplicitMembers() } } + subscript(other arg: Void) -> Other { Other() } } let _: ImplicitMembers = .implicit @@ -100,18 +101,32 @@ let _: ImplicitMembers = .createOptional()!.anotherOptional! let _: ImplicitMembers = .optional!.getAnotherOptional()! let _: ImplicitMembers = .createOptional()!.getAnotherOptional()! +let _: ImplicitMembers = .optional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{35-35= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{35-35=!}} +let _: ImplicitMembers = .implicit.anotherOptional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{51-51= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{51-51=!}} +let _: ImplicitMembers = .createOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{43-43= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{43-43=!}} +let _: ImplicitMembers = .implicit.getAnotherOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{56-56= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{56-56=!}} +let _: ImplicitMembers = .implicit[optional: ()] // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{49-49= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{49-49=!}} +let _: ImplicitMembers = .implicit[funcOptional: ()]() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{55-55= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{55-55=!}} + +// FIXME: Improve these diagnostics (should probably offer unwrapping, as above) +let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error{{cannot infer contextual base in reference to member 'implicit'}} expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{cannot infer contextual base in reference to member 'implicit'}} expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}} + + let _: ImplicitMembers = .other.implicit let _: ImplicitMembers = .implicit.anotherOther.implicit let _: ImplicitMembers = .createOther().implicit let _: ImplicitMembers = .implicit.getAnotherOther().implicit +let _: ImplicitMembers = .implicit[other: ()].implicit let _: ImplicitMembers = .other // expected-error {{member 'other' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} -let _: ImplicitMembers = .implicit.anotherOther // expected-error {{member 'implicit' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther // expected-error {{member 'anotherOther' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod() // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember.another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod().another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} let _: ImplicitMembers = .implicit.getAnotherOther() // expected-error {{member 'getAnotherOther()' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit[other: ()] // expected-error {{member 'subscript(other:)' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} let _: ImplicitMembers? = .implicit.another let _: ImplicitMembers? = .implicit.anotherOptional From 3b5deab1140912a4458663d44b1416988d9c6683 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 18:02:14 -0400 Subject: [PATCH 355/663] More diagnostic improvements --- include/swift/AST/DiagnosticsSema.def | 3 +++ lib/Sema/CSDiagnostics.cpp | 5 +++++ lib/Sema/CSSimplify.cpp | 4 ++-- test/expr/delayed-ident/member_chains.swift | 10 +++++----- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 5a0a494f535e6..e2176f6bd6c26 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -455,6 +455,9 @@ ERROR(cannot_convert_closure_result_nil,none, ERROR(cannot_convert_parent_type,none, "cannot convert parent type %0 to expected type %1", (Type, Type)) +ERROR(cannot_convert_chain_result_type,none, + "member chain produces result of type %0 but contextual base was inferred as %1", + (Type, Type)) NOTE(generic_argument_mismatch,none, "arguments to generic parameter %0 (%1 and %2) are expected to be equal", diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 5ea518d6a6281..225f8aeaf6ed1 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -755,6 +755,11 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() { break; } + case ConstraintLocator::UnresolvedMemberChainResult: { + diagnostic = diag::cannot_convert_chain_result_type; + break; + } + default: break; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 7a3ce7d18ee8f..3e93fadc44668 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -10056,10 +10056,10 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( impact = 10; } - if (locator->isLastElement()) { + if (locator->isLastElement()) { // If this is a contextual failure for an unresolved member, then increase // the impact to attempt other fixes first and avoid ambiguity. - impact = 5; + impact = 2; } if (recordFix(fix, impact)) diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index 9333047a27f12..dd13fdca5ddca 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -182,7 +182,7 @@ func implicit(_ i: inout ImplicitMembers) { if i == .createOptional()?.another {} } -struct ImplicitGeneric { +struct ImplicitGeneric { // expected-note4 {{arguments to generic parameter 'T' ('Int' and 'String') are expected to be equal}} static var implicit: ImplicitGeneric { ImplicitGeneric() } var another: ImplicitGeneric { ImplicitGeneric() } func getAnother() -> ImplicitGeneric { @@ -227,7 +227,7 @@ implicit(.implicitString.anotherStringInt) // Member types along the chain can have different generic arguments implicit(.implicit.anotherIntString.anotherStringInt) -implicit(.implicit.anotherString.anotherStringInt) // expected-error {{type of expression is ambiguous without more context}} -implicit(.implicit.getAnotherString().anotherStringInt) // expected-error {{type of expression is ambiguous without more context}} -implicit(.implicit.anotherString.getAnotherStringInt()) // expected-error {{type of expression is ambiguous without more context}} -implicit(.implicit.getAnotherString().getAnotherStringInt()) // expected-error {{type of expression is ambiguous without more context}} +implicit(.implicit.anotherString.anotherStringInt) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.getAnotherString().anotherStringInt) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.anotherString.getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.getAnotherString().getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} From 788d3f09530e5cf6d0534a7063e674e527d53a82 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 18:02:16 -0400 Subject: [PATCH 356/663] Fix missing call diagnostic --- lib/Sema/CSDiagnostics.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 225f8aeaf6ed1..5e2b733172a91 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2415,7 +2415,8 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const { if (getLocator()->isLastElement()) return false; - if (getLocator()->isLastElement()) + if (getLocator() + ->isLastElement()) return false; auto *srcFT = getFromType()->getAs(); From aedde34fecc3db6365d3ce7606fe16a022cd2fbe Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 18:02:21 -0400 Subject: [PATCH 357/663] [Sema] Move unresolved base tracking into CSGen Remove the tracking of unresolved base types from the constraint system, and place it entirely within the generation phase. We have other ways of getting at the base types after generation. --- lib/Sema/CSApply.cpp | 35 ++------ lib/Sema/CSGen.cpp | 173 +++++++++++++++++++++++------------- lib/Sema/CSSimplify.cpp | 35 ++++---- lib/Sema/CSSolver.cpp | 13 --- lib/Sema/ConstraintSystem.h | 64 ------------- 5 files changed, 134 insertions(+), 186 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 1e1775e464dd1..488fba7065882 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2753,30 +2753,16 @@ namespace { } Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { - // If constraint solving resolved the base type to an UnresolvedType, - // then we're in an ambiguity tolerant mode used for diagnostic - // generation. Just leave this as an unresolved member reference. - Type baseTy = simplifyType(solution.getUnresolvedMemberBaseType(expr)); - - if (baseTy->hasUnresolvedType()) { - cs.setType(expr, baseTy); - return expr; - } - auto &ctx = cs.getASTContext(); - - // Find the selected member. + // Find the selected member and base type. auto memberLocator = cs.getConstraintLocator( expr, ConstraintLocator::UnresolvedMember); auto selected = solution.getOverloadChoice(memberLocator); - - // If the member came by optional unwrapping, then unwrap the base type. - if (selected.choice.getKind() - == OverloadChoiceKind::DeclViaUnwrappedOptional) { - baseTy = baseTy->getOptionalObjectType(); - assert(baseTy - && "got unwrapped optional decl from non-optional base?!"); - } + + // Unresolved member lookup always happens in a metatype so dig out the + // instance type. + auto metaTy = selected.choice.getBaseType()->castTo(); + auto baseTy = cs.simplifyType(metaTy->getInstanceType()); // The base expression is simply the metatype of the base type. // FIXME: This location info is bogus. @@ -8449,15 +8435,6 @@ void Solution::setExprTypes(Expr *expr) const { expr->walk(SET); } -Type Solution::getUnresolvedMemberBaseType(UnresolvedMemberExpr *expr) const { - auto result = unresolvedMemberBaseTypes.find(expr); - if (result != unresolvedMemberBaseTypes.end()) - return result->second; - - auto &cs = getConstraintSystem(); - return cs.getUnresolvedMemberBaseType(expr); -} - /// MARK: SolutionResult implementation. SolutionResult SolutionResult::forSolved(Solution &&solution) { diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index cfe2e2bc2c2d7..75a29f088751b 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -74,6 +74,48 @@ static bool mergeRepresentativeEquivalenceClasses(ConstraintSystem &CS, return false; } +/// Find the next element in a chain of members. If this expression is (or +/// could be) the base of such a chain, this will return \c nullptr. +static Expr *getMemberChainSubExpr(Expr *expr) { + assert(expr && "getMemberChainSubExpr called with null expr!"); + if (auto *UDE = dyn_cast(expr)) { + return UDE->getBase(); + } else if (auto *CE = dyn_cast(expr)) { + return CE->getFn(); + } else if (auto *BOE = dyn_cast(expr)) { + return BOE->getSubExpr(); + } else if (auto *FVE = dyn_cast(expr)) { + return FVE->getSubExpr(); + } else if (auto *SE = dyn_cast(expr)) { + return SE->getBase(); + } else { + return nullptr; + } +} + +/// Returns the base of a chain of member accesses/method calls. Most +/// expressions do not participate in member chains, and just return \c this. +static Expr *getMemberChainBase(Expr *expr) { + if (auto *subExpr = getMemberChainSubExpr(expr)) + return getMemberChainBase(subExpr); + else + return expr; +} + +/// Whether this expression is a member of a member chain. +static bool isMemberChainMember(Expr *expr) { + return getMemberChainSubExpr(expr) != nullptr; +} +/// Whether this expression sits at the end of a chain of member accesses. +static bool isMemberChainTail(ConstraintSystem &cs, Expr *expr) { + assert(expr && "isMemberChainTail called with null expr!"); + // If this expression's parent is not itself part of a chain (or, this expr + // has no parent expr), this must be the tail of the chain. + Expr *parent = cs.getParentExpr(expr); + + return parent == nullptr || !isMemberChainMember(parent); +} + namespace { /// Internal struct for tracking information about types within a series @@ -792,6 +834,10 @@ namespace { /// Keep track of acceptable DiscardAssignmentExpr's. llvm::SmallPtrSet CorrectDiscardAssignmentExprs; + /// A map from the heads to the tails of each unresolved member chain found + /// during our walk. + llvm::MapVector UnresolvedBaseTypes; + /// Returns false and emits the specified diagnostic if the member reference /// base is a nil literal. Returns true otherwise. bool isValidBaseOfMemberRef(Expr *base, Diag<> diagnostic) { @@ -848,36 +894,6 @@ namespace { return tv; } - Type addUnresolvedMemberChainConstraints(Expr *expr, Type resultTy, - unsigned additionalOptions = 0) { - // If this is a member chain hanging off of an UnresolvedMemberExpr, - // and we're at the last element of the chain, then the contextual type - // (represented with a new type variable) must equal the base type. - if (CS.isMemberChainTail(expr)) { - auto *chainBaseExpr = CS.getMemberChainBase(expr); - if (auto *UME = dyn_cast(chainBaseExpr)) { - // Create a new type variable representing the result of the chain. - auto locator = CS.getConstraintLocator(expr, - ConstraintLocator::UnresolvedMemberChainResult); - auto chainResultTy = CS.createTypeVariable(locator, - additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape); - auto chainBaseTy = CS.getUnresolvedMemberBaseType(UME); - - // The result of this element of the chain must be convertible to the - // contextual type, and the contextual type must be equal to the base. - CS.addConstraint(ConstraintKind::Conversion, resultTy, chainResultTy, - locator); - CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, - CS.getConstraintLocator(UME, ConstraintLocator::MemberRefBase)); - - return chainResultTy; - } - } - - // Otherwise, just use the proposed result type. - return resultTy; - } - /// Add constraints for a subscript operation. Type addSubscriptConstraints( Expr *anchor, Type baseTy, Expr *index, @@ -1452,6 +1468,44 @@ namespace { Type visitDynamicMemberRefExpr(DynamicMemberRefExpr *expr) { llvm_unreachable("Already typechecked"); } + + void setUnresolvedBaseType(UnresolvedMemberExpr *UME, Type ty) { + UnresolvedBaseTypes.insert({UME, ty}); + } + + Type addUnresolvedMemberChainConstraints(UnresolvedMemberExpr *base, + Expr *tail, + Type resultTy) { + assert(isa(tail) || + isa(tail) || + isa(tail) || + isa(tail) || + isa(tail) || + isa(tail) && + "Unexpected expression at end of unresolved member chain"); + // Copy any type variable options from the result of the tail member to + // the result of the entire chain. + unsigned additionalOptions = 0; + if (auto *tvt = resultTy->getAs()) + additionalOptions = tvt->getImpl().getRawOptions(); + + // The contextual type (represented with a new type variable) must equal + // the base type. + auto locator = CS.getConstraintLocator(tail, + ConstraintLocator::UnresolvedMemberChainResult); + auto chainResultTy = CS.createTypeVariable(locator, + additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape); + auto chainBaseTy = UnresolvedBaseTypes.find(base)->second; + + // The result of this element of the chain must be convertible to the + // contextual type, and the contextual type must be equal to the base. + CS.addConstraint(ConstraintKind::Conversion, resultTy, chainResultTy, + locator); + CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, + CS.getConstraintLocator(base, ConstraintLocator::MemberRefBase)); + + return chainResultTy; + } virtual Type visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { auto baseLocator = CS.getConstraintLocator( @@ -1461,17 +1515,17 @@ namespace { expr->getArgument() ? FunctionRefKind::DoubleApply : FunctionRefKind::Compound; - auto memberLocator = CS.getConstraintLocator(expr, - ConstraintLocator::UnresolvedMember); + auto memberLocator + = CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember); // Since base type in this case is completely dependent on context it // should be marked as a potential hole. - auto baseTy = CS.createTypeVariable(baseLocator, - TVO_CanBindToHole | TVO_CanBindToNoEscape); - CS.setUnresolvedMemberBaseType(expr, baseTy); + auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape | + TVO_CanBindToHole); + setUnresolvedBaseType(expr, baseTy); - auto memberTy = CS.createTypeVariable(memberLocator, - TVO_CanBindToLValue | TVO_CanBindToNoEscape); + auto memberTy = CS.createTypeVariable( + memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); // An unresolved member expression '.member' is modeled as a value member // constraint @@ -1509,13 +1563,11 @@ namespace { CS.getConstraintLocator(expr), {expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()}); - return addUnresolvedMemberChainConstraints(expr, outputTy); + return outputTy; } - // Otherwise, add the usual constraints for an element of an unresolved - // member chain. - return addUnresolvedMemberChainConstraints(expr, memberTy, - TVO_CanBindToLValue); + // Otherwise, the result is just the type of the member. + return memberTy; } Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { @@ -1579,13 +1631,9 @@ namespace { return methodTy; } - auto resultTy = addMemberRefConstraints(expr, expr->getBase(), - expr->getName(), - expr->getFunctionRefKind(), - expr->getOuterAlternatives()); - - return addUnresolvedMemberChainConstraints(expr, resultTy, - TVO_CanBindToLValue); + return addMemberRefConstraints(expr, expr->getBase(), expr->getName(), + expr->getFunctionRefKind(), + expr->getOuterAlternatives()); } Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) { @@ -1744,13 +1792,10 @@ namespace { if (!isValidBaseOfMemberRef(base, diag::cannot_subscript_nil_literal)) return nullptr; - auto resultTy = addSubscriptConstraints(expr, CS.getType(base), - expr->getIndex(), - decl, expr->getArgumentLabels(), - expr->getUnlabeledTrailingClosureIndex()); - - return addUnresolvedMemberChainConstraints(expr, resultTy, - TVO_CanBindToLValue); + return addSubscriptConstraints(expr, CS.getType(base), + expr->getIndex(), + decl, expr->getArgumentLabels(), + expr->getUnlabeledTrailingClosureIndex()); } Type visitArrayExpr(ArrayExpr *expr) { @@ -2933,10 +2978,6 @@ namespace { resultType = fixedType; } - // If the ApplyExpr is a CallExpr, add chain constraints as necessary. - if (isa(expr)) - return addUnresolvedMemberChainConstraints(expr, resultType); - return resultType; } @@ -3247,8 +3288,7 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return addUnresolvedMemberChainConstraints(expr, objectTy, - TVO_CanBindToLValue); + return objectTy; } Type visitOptionalEvaluationExpr(OptionalEvaluationExpr *expr) { @@ -3283,7 +3323,7 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return addUnresolvedMemberChainConstraints(expr, objectTy); + return objectTy; } Type visitOpenExistentialExpr(OpenExistentialExpr *expr) { @@ -3818,6 +3858,13 @@ namespace { } if (auto type = CG.visit(expr)) { + if (isMemberChainTail(CG.getConstraintSystem(), expr)) { + auto *chainBase = getMemberChainBase(expr); + if (auto *UME = dyn_cast(chainBase)) { + type = CG.addUnresolvedMemberChainConstraints(UME, expr, type); + } + } + auto simplifiedType = CS.simplifyType(type); CS.setType(expr, simplifiedType); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 3e93fadc44668..922e25bdc45cf 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6777,24 +6777,25 @@ static ConstraintFix *validateInitializerRef(ConstraintSystem &cs, // then the type we're constructing may not actually be the base of the // UnresolvedMemberExpr--instead, it will be the type of the nested type // member. - if (locatorEndsWith(locator, ConstraintLocator::ConstructorMember)) { - auto *baseLocator = cs.getConstraintLocator(UME, - ConstraintLocator::UnresolvedMember); - auto result = llvm::find_if( - cs.getTypeVariables(), [&baseLocator](const TypeVariableType *typeVar) { - return typeVar->getImpl().getLocator() == baseLocator; - }); - assert(result != cs.getTypeVariables().end()); - baseType = cs.simplifyType(*result); + // We need to find type variable which represents contextual base. + auto *baseLocator = cs.getConstraintLocator( + UME, locatorEndsWith(locator, ConstraintLocator::ConstructorMember) + ? ConstraintLocator::UnresolvedMember + : ConstraintLocator::MemberRefBase); + + // FIXME: Type variables responsible for contextual base could be cached + // in the constraint system to speed up lookup. + auto result = llvm::find_if( + cs.getTypeVariables(), [&baseLocator](const TypeVariableType *typeVar) { + return typeVar->getImpl().getLocator() == baseLocator; + }); - // Otherwise, this an explicit reference to an initializer member - // (`.init(...)`). - } else { - // Constraint for member base is formed as '$T.Type[.getRValueType(); + // Constraint for member base is formed as '$T.Type[.(anchor)) { // Key path can't refer to initializers e.g. `\Type.init` return AllowInvalidRefInKeyPath::forRef(cs, init, locator); diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index ba10f3c128c73..8f0afc7b18b81 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -176,10 +176,6 @@ Solution ConstraintSystem::finalize() { solution.nodeTypes.insert(nodeType); } - for (auto &baseType : UnresolvedMemberBaseTypes) { - solution.unresolvedMemberBaseTypes.insert(baseType); - } - // Remember contextual types. solution.contextualTypes.assign( contextualTypes.begin(), contextualTypes.end()); @@ -255,11 +251,6 @@ void ConstraintSystem::applySolution(const Solution &solution) { setType(nodeType.first, nodeType.second); } - // Add the unresolved member base types back. - for (auto &baseType : solution.unresolvedMemberBaseTypes) { - setUnresolvedMemberBaseType(baseType.first, baseType.second); - } - // Add the contextual types. for (const auto &contextualType : solution.contextualTypes) { if (!getContextualTypeInfo(contextualType.first)) { @@ -484,7 +475,6 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs) numOpenedExistentialTypes = cs.OpenedExistentialTypes.size(); numDefaultedConstraints = cs.DefaultedConstraints.size(); numAddedNodeTypes = cs.addedNodeTypes.size(); - numUnresolvedMemberBaseTypes = cs.UnresolvedMemberBaseTypes.size(); numCheckedConformances = cs.CheckedConformances.size(); numDisabledConstraints = cs.solverState->getNumDisabledConstraints(); numFavoredConstraints = cs.solverState->getNumFavoredConstraints(); @@ -563,9 +553,6 @@ ConstraintSystem::SolverScope::~SolverScope() { } truncate(cs.addedNodeTypes, numAddedNodeTypes); - // Remove any unresolved member base types. - truncate(cs.UnresolvedMemberBaseTypes, numUnresolvedMemberBaseTypes); - // Remove any conformances checked along the current path. truncate(cs.CheckedConformances, numCheckedConformances); diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index a9018f1a302e9..bc95ed45c0b55 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1080,9 +1080,6 @@ class Solution { /// The node -> type mappings introduced by this solution. llvm::DenseMap nodeTypes; - /// The unresolved member base types introduced by this solution. - llvm::MapVector unresolvedMemberBaseTypes; - /// Contextual types introduced by this solution. std::vector> contextualTypes; @@ -1198,9 +1195,6 @@ class Solution { /// "resolved" concrete type. Type getResolvedType(ASTNode node) const; - /// Retrieve the type of a particular \c UnresolvedMemberExpr's base. - Type getUnresolvedMemberBaseType(UnresolvedMemberExpr *expr) const; - /// Resolve type variables present in the raw type, using generic parameter /// types where possible. Type resolveInterfaceType(Type type) const; @@ -2056,9 +2050,6 @@ class ConstraintSystem { llvm::DenseMap OpenedParameterTypes; - /// Maps \c UnresolvedMemberExprs to their (implicit) base types. - llvm::MapVector UnresolvedMemberBaseTypes; - /// The set of constraint restrictions used to reach the /// current constraint system. /// @@ -2580,8 +2571,6 @@ class ConstraintSystem { unsigned numAddedNodeTypes; - unsigned numUnresolvedMemberBaseTypes; - unsigned numCheckedConformances; unsigned numDisabledConstraints; @@ -2884,17 +2873,6 @@ class ConstraintSystem { return CTP_Unused; } - void setUnresolvedMemberBaseType(UnresolvedMemberExpr *expr, Type type) { - assert(expr && "Expected non-null expression"); - assert(type && "Expected non-null type"); - UnresolvedMemberBaseTypes[expr] = type; - } - - Type getUnresolvedMemberBaseType(UnresolvedMemberExpr *expr) { - assert(expr && "Expected non-null expression"); - return UnresolvedMemberBaseTypes.find(expr)->second; - } - void setSolutionApplicationTarget( SolutionApplicationTargetsKey key, SolutionApplicationTarget target) { assert(solutionApplicationTargets.count(key) == 0 && @@ -3044,48 +3022,6 @@ class ConstraintSystem { bool isDeclUnavailable(const Decl *D, ConstraintLocator *locator = nullptr) const; - /// Find the next element in a chain of members. If this expression is (or - /// could be) the base of such a chain, this will return \c nullptr. - Expr *getMemberChainSubExpr(Expr *expr) { - assert(expr && "isMemberChainSubExpr called with null expr!"); - if (auto *UDE = dyn_cast(expr)) { - return UDE->getBase(); - } else if (auto *CE = dyn_cast(expr)) { - return CE->getFn(); - } else if (auto *BOE = dyn_cast(expr)) { - return BOE->getSubExpr(); - } else if (auto *FVE = dyn_cast(expr)) { - return FVE->getSubExpr(); - } else if (auto *SE = dyn_cast(expr)) { - return SE->getBase(); - } else { - return nullptr; - } - } - - /// Returns the base of a chain of member accesses/method calls. Most - /// expressions do not participate in member chains, and just return \c this. - Expr *getMemberChainBase(Expr *expr) { - if (auto *subExpr = getMemberChainSubExpr(expr)) - return getMemberChainBase(subExpr); - else - return expr; - } - - /// Whether this expression is a member of a member chain. - bool isMemberChainMember(Expr *expr) { - return getMemberChainSubExpr(expr) != nullptr; - } - /// Whether this expression sits at the end of a chain of member accesses. - bool isMemberChainTail(Expr *expr) { - assert(expr && "isMemberChainTail called with null expr!"); - // If this expression's parent is not itself part of a chain (or, this expr - // has no parent expr), this must be the tail of the chain. - Expr *parent = getParentExpr(expr); - - return parent == nullptr || !isMemberChainMember(parent); - } - public: /// Whether we should attempt to fix problems. From 4e9b7b20dbc5d98e6f504116a19d80889cb28568 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 18:02:23 -0400 Subject: [PATCH 358/663] [Sema] Inject implicit ParenExpr for unresolved member chains In order to give unresolved member chain result types visibility in the AST, we inject an implicit ParenExpr in CSGen that lives only for the duration of type checking, and gets removed during solution application. --- include/swift/AST/Expr.h | 13 +++++++++++-- lib/Sema/CSApply.cpp | 12 ++++++++++++ lib/Sema/CSGen.cpp | 28 ++++++++++++++++++++-------- lib/Sema/CSSimplify.cpp | 3 +++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 6e9b24921b1ff..ca8e5d1fc9164 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2048,13 +2048,14 @@ class DotSelfExpr : public IdentityExpr { /// has tuple type, of course). class ParenExpr : public IdentityExpr { SourceLoc LParenLoc, RParenLoc; - + bool IsUnresolvedMemberChainPlaceholder; public: ParenExpr(SourceLoc lploc, Expr *subExpr, SourceLoc rploc, bool hasTrailingClosure, Type ty = Type()) : IdentityExpr(ExprKind::Paren, subExpr, ty), - LParenLoc(lploc), RParenLoc(rploc) { + LParenLoc(lploc), RParenLoc(rploc), + IsUnresolvedMemberChainPlaceholder(false) { Bits.ParenExpr.HasTrailingClosure = hasTrailingClosure; assert(lploc.isValid() == rploc.isValid() && "Mismatched source location information"); @@ -2086,6 +2087,14 @@ class ParenExpr : public IdentityExpr { return hasTrailingClosure() ? Optional(0) : None; } + bool isUnresolvedMemberChainPlaceholder() const { + return IsUnresolvedMemberChainPlaceholder; + } + + void setIsUnresolvedMemberChainPlaceholder() { + IsUnresolvedMemberChainPlaceholder = true; + } + static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; } }; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 488fba7065882..63cde612d292e 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3259,6 +3259,18 @@ namespace { } Expr *visitParenExpr(ParenExpr *expr) { + // If this was an implicit ParenExpr inserted to give an unresolved member + // chain result type visibility in the AST (see + // ConstraintWalker::walkToExprPost), remove it from the AST now that we + // have a solution. + if (expr->isUnresolvedMemberChainPlaceholder()) { + auto *subExpr = expr->getSubExpr(); + auto type = simplifyType(cs.getType(expr)); + subExpr = coerceToType(subExpr, type, cs.getConstraintLocator(subExpr)); + cs.setType(subExpr, type); + return subExpr; + } + return simplifyExprType(expr); } diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 75a29f088751b..818484e8ff5c0 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1493,16 +1493,18 @@ namespace { // the base type. auto locator = CS.getConstraintLocator(tail, ConstraintLocator::UnresolvedMemberChainResult); - auto chainResultTy = CS.createTypeVariable(locator, - additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape); + auto tvo = additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape; + auto chainResultTy = CS.createTypeVariable(locator, tvo); auto chainBaseTy = UnresolvedBaseTypes.find(base)->second; // The result of this element of the chain must be convertible to the // contextual type, and the contextual type must be equal to the base. + CS.addConstraint(ConstraintKind::Conversion, resultTy, chainBaseTy, + CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); CS.addConstraint(ConstraintKind::Conversion, resultTy, chainResultTy, locator); CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, - CS.getConstraintLocator(base, ConstraintLocator::MemberRefBase)); + locator); return chainResultTy; } @@ -3858,17 +3860,27 @@ namespace { } if (auto type = CG.visit(expr)) { + + auto simplifiedType = CS.simplifyType(type); + + CS.setType(expr, simplifiedType); + + // If this is the end of a member chain, inject an implicit ParenExpr + // to link the contextual type to the (implicit) base of the chain. if (isMemberChainTail(CG.getConstraintSystem(), expr)) { auto *chainBase = getMemberChainBase(expr); if (auto *UME = dyn_cast(chainBase)) { - type = CG.addUnresolvedMemberChainConstraints(UME, expr, type); + auto chainTy = CG.addUnresolvedMemberChainConstraints(UME, expr, + simplifiedType); + auto *PE = new (CS.getASTContext()) ParenExpr(SourceLoc(), expr, + SourceLoc(), false); + PE->setImplicit(); + PE->setIsUnresolvedMemberChainPlaceholder(); + CS.setType(PE, chainTy); + return PE; } } - auto simplifiedType = CS.simplifyType(type); - - CS.setType(expr, simplifiedType); - return expr; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 922e25bdc45cf..d24656ca0497e 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4306,6 +4306,9 @@ bool ConstraintSystem::repairFailures( break; } + case ConstraintLocator::RValueAdjustment: + return true; + case ConstraintLocator::UnresolvedMemberChainResult: { if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, locator)) From f5845666e6a59528ece6c943e281dbe9125faead Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 18:02:26 -0400 Subject: [PATCH 359/663] [AST] Introduce UnresolvedMemberChainResultExpr Introduce a new expression type for representing the result of an unresolved member chain. Use this expression type instead of an implicit ParenExpr for giving unresolved member chain result types representation in the AST during type checking. --- include/swift/AST/Expr.h | 28 ++++++++++++++++++---------- include/swift/AST/ExprNodes.def | 3 ++- lib/AST/ASTDumper.cpp | 7 ++++++- lib/AST/Expr.cpp | 2 ++ lib/Sema/CSApply.cpp | 25 +++++++++++++------------ lib/Sema/CSGen.cpp | 10 ++++------ 6 files changed, 45 insertions(+), 30 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index ca8e5d1fc9164..7ce334aba0771 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2048,14 +2048,13 @@ class DotSelfExpr : public IdentityExpr { /// has tuple type, of course). class ParenExpr : public IdentityExpr { SourceLoc LParenLoc, RParenLoc; - bool IsUnresolvedMemberChainPlaceholder; + public: ParenExpr(SourceLoc lploc, Expr *subExpr, SourceLoc rploc, bool hasTrailingClosure, Type ty = Type()) : IdentityExpr(ExprKind::Paren, subExpr, ty), - LParenLoc(lploc), RParenLoc(rploc), - IsUnresolvedMemberChainPlaceholder(false) { + LParenLoc(lploc), RParenLoc(rploc) { Bits.ParenExpr.HasTrailingClosure = hasTrailingClosure; assert(lploc.isValid() == rploc.isValid() && "Mismatched source location information"); @@ -2087,15 +2086,24 @@ class ParenExpr : public IdentityExpr { return hasTrailingClosure() ? Optional(0) : None; } - bool isUnresolvedMemberChainPlaceholder() const { - return IsUnresolvedMemberChainPlaceholder; - } + static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; } +}; - void setIsUnresolvedMemberChainPlaceholder() { - IsUnresolvedMemberChainPlaceholder = true; - } +/// Represents the result of a chain of accesses or calls hanging off of an +/// \c UnresolvedMemberExpr at the root. This is only used during type checking +/// to give the result type of such a chain representation in the AST. This +/// expression type is always implicit. +class UnresolvedMemberChainResultExpr : public IdentityExpr { +public: + UnresolvedMemberChainResultExpr(Expr *subExpr, Type ty = Type()) + : IdentityExpr(ExprKind::UnresolvedMemberChainResult, subExpr, ty, + /*isImplicit=*/true) {} - static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; } + SWIFT_FORWARD_SOURCE_LOCS_TO(getSubExpr()) + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::UnresolvedMemberChainResult; + } }; /// AwaitExpr - An 'await' surrounding an expression, marking that the diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 53ee2da310a42..7c98a83c0afd9 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -104,7 +104,8 @@ ABSTRACT_EXPR(Identity, Expr) EXPR(Paren, IdentityExpr) EXPR(DotSelf, IdentityExpr) EXPR(Await, IdentityExpr) - EXPR_RANGE(Identity, Paren, Await) + EXPR(UnresolvedMemberChainResult, IdentityExpr) + EXPR_RANGE(Identity, Paren, UnresolvedMemberChainResult) ABSTRACT_EXPR(AnyTry, Expr) EXPR(Try, AnyTryExpr) EXPR(ForceTry, AnyTryExpr) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index d8352e9c62e2c..fa9efd6ba4c2f 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2135,7 +2135,12 @@ class PrintExpr : public ExprVisitor { printRec(E->getSubExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitUnresolvedMemberChainResultExpr(UnresolvedMemberChainResultExpr *E){ + printCommon(E, "unresolved_member_chain_expr"); + OS << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitTupleExpr(TupleExpr *E) { printCommon(E, "tuple_expr"); if (E->hasTrailingClosure()) diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 95a290a0d303c..113b8e499a136 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -288,6 +288,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const { return cast(this) ->getSubExpr()->getReferencedDecl(stopAtParenExpr); + PASS_THROUGH_REFERENCE(UnresolvedMemberChainResult, getSubExpr); PASS_THROUGH_REFERENCE(DotSelf, getSubExpr); PASS_THROUGH_REFERENCE(Await, getSubExpr); PASS_THROUGH_REFERENCE(Try, getSubExpr); @@ -606,6 +607,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::Paren: case ExprKind::DotSelf: + case ExprKind::UnresolvedMemberChainResult: case ExprKind::Tuple: case ExprKind::Array: case ExprKind::Dictionary: diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 63cde612d292e..f20d43efe7c5a 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3259,21 +3259,22 @@ namespace { } Expr *visitParenExpr(ParenExpr *expr) { - // If this was an implicit ParenExpr inserted to give an unresolved member - // chain result type visibility in the AST (see - // ConstraintWalker::walkToExprPost), remove it from the AST now that we - // have a solution. - if (expr->isUnresolvedMemberChainPlaceholder()) { - auto *subExpr = expr->getSubExpr(); - auto type = simplifyType(cs.getType(expr)); - subExpr = coerceToType(subExpr, type, cs.getConstraintLocator(subExpr)); - cs.setType(subExpr, type); - return subExpr; - } - return simplifyExprType(expr); } + Expr *visitUnresolvedMemberChainResultExpr( + UnresolvedMemberChainResultExpr *expr) { + // Since this expression only exists to give the result type of an + // unresolved member chain visibility in the AST, remove it from the AST + // now that we have a solution and coerce the subexpr to the resulting + // type. + auto *subExpr = expr->getSubExpr(); + auto type = simplifyType(cs.getType(expr)); + subExpr = coerceToType(subExpr, type, cs.getConstraintLocator(subExpr)); + cs.setType(subExpr, type); + return subExpr; + } + Expr *visitTupleExpr(TupleExpr *expr) { return simplifyExprType(expr); } diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 818484e8ff5c0..ab1e145afa0be 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3872,12 +3872,10 @@ namespace { if (auto *UME = dyn_cast(chainBase)) { auto chainTy = CG.addUnresolvedMemberChainConstraints(UME, expr, simplifiedType); - auto *PE = new (CS.getASTContext()) ParenExpr(SourceLoc(), expr, - SourceLoc(), false); - PE->setImplicit(); - PE->setIsUnresolvedMemberChainPlaceholder(); - CS.setType(PE, chainTy); - return PE; + auto *resultExpr = + new (CS.getASTContext()) UnresolvedMemberChainResultExpr(expr); + CS.setType(resultExpr, chainTy); + return resultExpr; } } From d78b59c8832abb5fb6239e798d29de65d657e97c Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 31 Jul 2020 22:38:23 -0400 Subject: [PATCH 360/663] [Sema] Prefer LValueType during solution scoring When comparing solutions, prefer LValueType(T) to T since we can convert lvalues to rvalues via a load during solution application. --- lib/Sema/CSRanking.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index 0d45d781c6212..c4c82327be892 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -1188,6 +1188,21 @@ SolutionCompareResult ConstraintSystem::compareSolutions( continue; } + // Prefer binding to an l-value over an r-value of the same type, since we + // can load from an l-value to produce an r-value during solution + // application. + if (type1->is() != type2->is()) { + auto rValTy1 = type1->getRValueType(); + auto rValTy2 = type2->getRValueType(); + if (rValTy1->isEqual(rValTy2)) { + if (type1->is()) + ++score1; + else + ++score2; + } + continue; + } + // FIXME: // This terrible hack is in place to support equality comparisons of non- // equatable option types to 'nil'. Until we have a way to constrain a type From e0e3babcd08ca6b43238177eec3e735c76afec94 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Sun, 2 Aug 2020 23:38:47 -0400 Subject: [PATCH 361/663] [Sema] Change anchor of unresolved chain result type Instead of creating the type variable for the unresolved member chain at the location of the last member, we now create it at the associated UnresolvedMemberChainResultExpr. Previously, when the final element of a chain was a ForceValueExpr, the chain result type got caught up in the logic used to allow ForceValueExprs to properly infer lvalue types. By separating the result type variable from the last member of the chain, we make sure to keep that logic focused only on ForceValueExpr. --- lib/Sema/CSGen.cpp | 13 +++++--- lib/Sema/CSRanking.cpp | 15 --------- lib/Sema/ConstraintSystem.cpp | 2 ++ test/expr/delayed-ident/member_chains.swift | 34 +++++++++++++++++++-- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index ab1e145afa0be..41f42cf4b8ead 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1475,6 +1475,7 @@ namespace { Type addUnresolvedMemberChainConstraints(UnresolvedMemberExpr *base, Expr *tail, + UnresolvedMemberChainResultExpr *result, Type resultTy) { assert(isa(tail) || isa(tail) || @@ -1491,7 +1492,7 @@ namespace { // The contextual type (represented with a new type variable) must equal // the base type. - auto locator = CS.getConstraintLocator(tail, + auto locator = CS.getConstraintLocator(result, ConstraintLocator::UnresolvedMemberChainResult); auto tvo = additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape; auto chainResultTy = CS.createTypeVariable(locator, tvo); @@ -3865,15 +3866,17 @@ namespace { CS.setType(expr, simplifiedType); - // If this is the end of a member chain, inject an implicit ParenExpr - // to link the contextual type to the (implicit) base of the chain. + // If this is the end of an unresolved member chain, inject the + // appropriate constraints to link the contextual type to the (implicit) + // base of the chain. if (isMemberChainTail(CG.getConstraintSystem(), expr)) { auto *chainBase = getMemberChainBase(expr); + auto *resultExpr = + new (CS.getASTContext()) UnresolvedMemberChainResultExpr(expr); if (auto *UME = dyn_cast(chainBase)) { auto chainTy = CG.addUnresolvedMemberChainConstraints(UME, expr, + resultExpr, simplifiedType); - auto *resultExpr = - new (CS.getASTContext()) UnresolvedMemberChainResultExpr(expr); CS.setType(resultExpr, chainTy); return resultExpr; } diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index c4c82327be892..0d45d781c6212 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -1188,21 +1188,6 @@ SolutionCompareResult ConstraintSystem::compareSolutions( continue; } - // Prefer binding to an l-value over an r-value of the same type, since we - // can load from an l-value to produce an r-value during solution - // application. - if (type1->is() != type2->is()) { - auto rValTy1 = type1->getRValueType(); - auto rValTy2 = type2->getRValueType(); - if (rValTy1->isEqual(rValTy2)) { - if (type1->is()) - ++score1; - else - ++score2; - } - continue; - } - // FIXME: // This terrible hack is in place to support equality comparisons of non- // equatable option types to 'nil'. Until we have a way to constrain a type diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 322dc620c19de..dad11b3fd25ea 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3860,6 +3860,8 @@ void constraints::simplifyLocator(ASTNode &anchor, } case ConstraintLocator::UnresolvedMemberChainResult: { + auto *resultExpr = getAsExpr(anchor); + anchor = resultExpr->getSubExpr(); path = path.slice(1); continue; } diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index dd13fdca5ddca..7077c37e2ee87 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -26,6 +26,10 @@ struct ImplicitMembers: Equatable { static var superOptional: ImplicitMembers??? = ImplicitMembers() var another: ImplicitMembers { ImplicitMembers() } + var anotherMutable: ImplicitMembers { + get { ImplicitMembers() } + set {} + } func getAnother() -> ImplicitMembers { ImplicitMembers() @@ -36,6 +40,10 @@ struct ImplicitMembers: Equatable { } var anotherOptional: ImplicitMembers? { ImplicitMembers() } + var anotherOptionalMutable: ImplicitMembers? { + get { ImplicitMembers() } + set {} + } func getAnotherOptional() -> ImplicitMembers? { ImplicitMembers() @@ -45,8 +53,14 @@ struct ImplicitMembers: Equatable { ImplicitMembers() } - subscript(arg: Void) -> ImplicitMembers { ImplicitMembers() } - subscript(optional arg: Void) -> ImplicitMembers? { ImplicitMembers() } + subscript(arg: Void) -> ImplicitMembers { + get { ImplicitMembers() } + set {} + } + subscript(optional arg: Void) -> ImplicitMembers? { + get { ImplicitMembers() } + set {} + } subscript(func arg: Void) -> (() -> ImplicitMembers) { { ImplicitMembers() } } subscript(funcOptional arg: Void) -> (() -> ImplicitMembers?) { { ImplicitMembers() } } subscript(optionalFunc arg: Void) -> (() -> ImplicitMembers)? { { ImplicitMembers() } } @@ -182,6 +196,22 @@ func implicit(_ i: inout ImplicitMembers) { if i == .createOptional()?.another {} } +func testLValues() { + let local = ImplicitMembers(); + + .implicit = local; + .implicit.anotherMutable = local; + .implicit.anotherOptionalMutable? = local; + .implicit.anotherOptionalMutable! = local; + .implicit[()] = local; + .implicit[()].anotherMutable = local; + .optional?[optional: ()]?.anotherOptionalMutable! = local + + // FIXME: These should probably be allowed + //.implicit.anotherOptionalMutable = local; + //.optional = local; +} + struct ImplicitGeneric { // expected-note4 {{arguments to generic parameter 'T' ('Int' and 'String') are expected to be equal}} static var implicit: ImplicitGeneric { ImplicitGeneric() } var another: ImplicitGeneric { ImplicitGeneric() } From 4331e26bcdb85350efad20cd6cd7be5ee444a829 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 3 Aug 2020 17:31:32 -0400 Subject: [PATCH 362/663] [Sema] Move UnresolvedMemberChainResultExpr creation to walkToExprPre The old method of generating this placeholder expression caused issues when constraints had to be recursively regenerated during solving. Now, we generate UnresolvedMemberChainResultExprs in walkToExprPre, and use ASTWalker::Parent instead of ConstraintSystem::getParentExpr to find the parent of the chain tail. This also lets us generate the chain constraints as part of the normal ConstraintGenerator visit, rather than as an extra walkToExprPost step. --- lib/Sema/CSDiagnostics.cpp | 7 ++ lib/Sema/CSGen.cpp | 133 +++++++++++++++++++++---------------- 2 files changed, 83 insertions(+), 57 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 5e2b733172a91..5b1049b46e067 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3461,6 +3461,13 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const { if (!(parentExpr && isa(expr))) return false; + if (!isa(parentExpr)) + return false; + + parentExpr = findParentExpr(parentExpr); + if (!parentExpr) + return false; + auto parentType = getType(parentExpr); if (!parentType->isKnownStdlibCollectionType() && !parentType->is()) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 41f42cf4b8ead..702bbc0b57ecb 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -95,11 +95,11 @@ static Expr *getMemberChainSubExpr(Expr *expr) { /// Returns the base of a chain of member accesses/method calls. Most /// expressions do not participate in member chains, and just return \c this. -static Expr *getMemberChainBase(Expr *expr) { +static UnresolvedMemberExpr *getUnresolvedMemberChainBase(Expr *expr) { if (auto *subExpr = getMemberChainSubExpr(expr)) - return getMemberChainBase(subExpr); + return getUnresolvedMemberChainBase(subExpr); else - return expr; + return dyn_cast(expr); } /// Whether this expression is a member of a member chain. @@ -107,12 +107,10 @@ static bool isMemberChainMember(Expr *expr) { return getMemberChainSubExpr(expr) != nullptr; } /// Whether this expression sits at the end of a chain of member accesses. -static bool isMemberChainTail(ConstraintSystem &cs, Expr *expr) { +static bool isMemberChainTail(Expr *expr, Expr *parent) { assert(expr && "isMemberChainTail called with null expr!"); // If this expression's parent is not itself part of a chain (or, this expr // has no parent expr), this must be the tail of the chain. - Expr *parent = cs.getParentExpr(expr); - return parent == nullptr || !isMemberChainMember(parent); } @@ -834,10 +832,14 @@ namespace { /// Keep track of acceptable DiscardAssignmentExpr's. llvm::SmallPtrSet CorrectDiscardAssignmentExprs; - /// A map from the heads to the tails of each unresolved member chain found - /// during our walk. + /// A map from each UnresolvedMemberExpr to the respective (implicit) base + /// found during our walk. llvm::MapVector UnresolvedBaseTypes; + /// A map from the tail of each unresolved member chain to the respective + /// base of the chain. + llvm::MapVectorUnresolvedChainBases; + /// Returns false and emits the specified diagnostic if the member reference /// base is a nil literal. Returns true otherwise. bool isValidBaseOfMemberRef(Expr *base, Diag<> diagnostic) { @@ -1473,41 +1475,20 @@ namespace { UnresolvedBaseTypes.insert({UME, ty}); } - Type addUnresolvedMemberChainConstraints(UnresolvedMemberExpr *base, - Expr *tail, - UnresolvedMemberChainResultExpr *result, - Type resultTy) { - assert(isa(tail) || - isa(tail) || - isa(tail) || - isa(tail) || - isa(tail) || - isa(tail) && - "Unexpected expression at end of unresolved member chain"); - // Copy any type variable options from the result of the tail member to - // the result of the entire chain. - unsigned additionalOptions = 0; - if (auto *tvt = resultTy->getAs()) - additionalOptions = tvt->getImpl().getRawOptions(); - - // The contextual type (represented with a new type variable) must equal - // the base type. - auto locator = CS.getConstraintLocator(result, - ConstraintLocator::UnresolvedMemberChainResult); - auto tvo = additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape; - auto chainResultTy = CS.createTypeVariable(locator, tvo); - auto chainBaseTy = UnresolvedBaseTypes.find(base)->second; + Type getUnresolvedBaseType(UnresolvedMemberExpr *UME) { + auto result = UnresolvedBaseTypes.find(UME); + assert(result != UnresolvedBaseTypes.end()); + return result->second; + } - // The result of this element of the chain must be convertible to the - // contextual type, and the contextual type must be equal to the base. - CS.addConstraint(ConstraintKind::Conversion, resultTy, chainBaseTy, - CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); - CS.addConstraint(ConstraintKind::Conversion, resultTy, chainResultTy, - locator); - CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, - locator); + void setUnresolvedChainBase(Expr *tail, UnresolvedMemberExpr *base) { + UnresolvedChainBases.insert({tail, base}); + } - return chainResultTy; + UnresolvedMemberExpr *getUnresolvedChainBase(Expr *tail) { + auto result = UnresolvedChainBases.find(tail); + assert(result != UnresolvedChainBases.end()); + return result->second; } virtual Type visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { @@ -1573,6 +1554,46 @@ namespace { return memberTy; } + Type visitUnresolvedMemberChainResultExpr( + UnresolvedMemberChainResultExpr *expr) { + auto *tail = expr->getSubExpr(); + assert(isa(tail) || + isa(tail) || + isa(tail) || + isa(tail) || + isa(tail) || + isa(tail) && + "Unexpected expression at end of unresolved member chain"); + + auto memberTy = CS.getType(tail); + auto *base = getUnresolvedChainBase(tail); + + // Copy any type variable options from the result of the tail member to + // the result of the entire chain. + unsigned additionalOptions = 0; + if (auto *tvt = memberTy->getAs()) + additionalOptions = tvt->getImpl().getRawOptions(); + + // The contextual type (represented with a new type variable) must equal + // the base type. + auto locator = CS.getConstraintLocator(expr, + ConstraintLocator::UnresolvedMemberChainResult); + auto tvo = additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape; + auto chainResultTy = CS.createTypeVariable(locator, tvo); + auto chainBaseTy = UnresolvedBaseTypes.find(base)->second; + + // The result of this element of the chain must be convertible to the + // contextual type, and the contextual type must be equal to the base. + CS.addConstraint(ConstraintKind::Conversion, memberTy, chainBaseTy, + CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); + CS.addConstraint(ConstraintKind::Conversion, memberTy, chainResultTy, + locator); + CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, + locator); + + return chainResultTy; + } + Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { // If this is Builtin.type_join*, just return any type and move // on since we're going to discard this, and creating any type @@ -3819,6 +3840,20 @@ namespace { if (auto *assignment = dyn_cast(expr)) CG.markAcceptableDiscardExprs(assignment->getDest()); + // If we find an unresolved member chain, wrap it in an + // UnresolvedMemberChainResultExpr (unless this has already been done) + // and generate constraints for the wrapped expression. + auto *parent = Parent.getAsExpr(); + if (isMemberChainTail(expr, parent)) { + if (auto *UME = getUnresolvedMemberChainBase(expr)) { + if (!parent || !isa(parent)) { + CG.setUnresolvedChainBase(expr, UME); + auto &context = CG.getConstraintSystem().getASTContext(); + expr = new (context) UnresolvedMemberChainResultExpr(expr); + } + } + } + return { true, expr }; } @@ -3866,22 +3901,6 @@ namespace { CS.setType(expr, simplifiedType); - // If this is the end of an unresolved member chain, inject the - // appropriate constraints to link the contextual type to the (implicit) - // base of the chain. - if (isMemberChainTail(CG.getConstraintSystem(), expr)) { - auto *chainBase = getMemberChainBase(expr); - auto *resultExpr = - new (CS.getASTContext()) UnresolvedMemberChainResultExpr(expr); - if (auto *UME = dyn_cast(chainBase)) { - auto chainTy = CG.addUnresolvedMemberChainConstraints(UME, expr, - resultExpr, - simplifiedType); - CS.setType(resultExpr, chainTy); - return resultExpr; - } - } - return expr; } From aade4aa74b4b60942e0dc612da0490e17a88e8e7 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 3 Aug 2020 17:37:37 -0400 Subject: [PATCH 363/663] [Localization] Add new diagnostics to localization file --- localization/diagnostics/en.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index b346b96b115cc..b53a3154d8856 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -2224,6 +2224,10 @@ - id: expected_parens_in_contextual_member msg: "member %0 is a function; did you mean to call it?" +- id: expected_parens_in_contextual_member_type + msg: >- + member %0 is a function that produces expected type %1; did you mean to call it? + - id: expected_result_in_contextual_member msg: "member %0 in %2 produces result of type %1, but context expects %2" @@ -2518,6 +2522,10 @@ - id: cannot_convert_parent_type msg: "cannot convert parent type %0 to expected type %1" +- id: cannot_convert_chain_result_type + msg: >- + member chain produces result of type %0 but contextual base was inferred as %1 + - id: generic_argument_mismatch msg: "arguments to generic parameter %0 (%1 and %2) are expected to be equal" From 5394e6b2d60c56dfc5d453924f0feb5726f111f0 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 3 Aug 2020 17:39:51 -0400 Subject: [PATCH 364/663] [Sema] Use getMetatypeInstanceType instead of casting to MetatypeType --- lib/Sema/CSApply.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index f20d43efe7c5a..ca4979d01fcfa 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2761,8 +2761,7 @@ namespace { // Unresolved member lookup always happens in a metatype so dig out the // instance type. - auto metaTy = selected.choice.getBaseType()->castTo(); - auto baseTy = cs.simplifyType(metaTy->getInstanceType()); + auto baseTy = selected.choice.getBaseType()->getMetatypeInstanceType(); // The base expression is simply the metatype of the base type. // FIXME: This location info is bogus. From c33ad11ff67e95b8c788b8623aad593e96120a96 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 3 Aug 2020 17:51:28 -0400 Subject: [PATCH 365/663] [Sema] Apply clang-format --- lib/Sema/CSApply.cpp | 2 +- lib/Sema/CSGen.cpp | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index ca4979d01fcfa..53afe327a3fd3 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3262,7 +3262,7 @@ namespace { } Expr *visitUnresolvedMemberChainResultExpr( - UnresolvedMemberChainResultExpr *expr) { + UnresolvedMemberChainResultExpr *expr) { // Since this expression only exists to give the result type of an // unresolved member chain visibility in the AST, remove it from the AST // now that we have a solution and coerce the subexpr to the resulting diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 702bbc0b57ecb..1b00dd2b72652 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1505,7 +1505,7 @@ namespace { // Since base type in this case is completely dependent on context it // should be marked as a potential hole. auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape | - TVO_CanBindToHole); + TVO_CanBindToHole); setUnresolvedBaseType(expr, baseTy); auto memberTy = CS.createTypeVariable( @@ -1555,15 +1555,13 @@ namespace { } Type visitUnresolvedMemberChainResultExpr( - UnresolvedMemberChainResultExpr *expr) { + UnresolvedMemberChainResultExpr *expr) { auto *tail = expr->getSubExpr(); - assert(isa(tail) || - isa(tail) || - isa(tail) || - isa(tail) || + assert(isa(tail) || isa(tail) || + isa(tail) || isa(tail) || isa(tail) || isa(tail) && - "Unexpected expression at end of unresolved member chain"); + "Unexpected expression at end of unresolved member chain"); auto memberTy = CS.getType(tail); auto *base = getUnresolvedChainBase(tail); @@ -1576,16 +1574,17 @@ namespace { // The contextual type (represented with a new type variable) must equal // the base type. - auto locator = CS.getConstraintLocator(expr, - ConstraintLocator::UnresolvedMemberChainResult); + auto locator = CS.getConstraintLocator( + expr, ConstraintLocator::UnresolvedMemberChainResult); auto tvo = additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape; auto chainResultTy = CS.createTypeVariable(locator, tvo); auto chainBaseTy = UnresolvedBaseTypes.find(base)->second; // The result of this element of the chain must be convertible to the // contextual type, and the contextual type must be equal to the base. - CS.addConstraint(ConstraintKind::Conversion, memberTy, chainBaseTy, - CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); + CS.addConstraint( + ConstraintKind::Conversion, memberTy, chainBaseTy, + CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); CS.addConstraint(ConstraintKind::Conversion, memberTy, chainResultTy, locator); CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, From 1e27f26b0126ef5c5b8af32d948c6723d73aa315 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 3 Aug 2020 18:12:38 -0400 Subject: [PATCH 366/663] [Sema] Always cache the unresolved chain base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even when we’ve already visited the expression for constraint generation (signified by the presence of an UnresolvedMemberChainResultExpr) we should still cache the chain base. --- lib/Sema/CSGen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 1b00dd2b72652..0ddb8919ed0bf 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3845,8 +3845,8 @@ namespace { auto *parent = Parent.getAsExpr(); if (isMemberChainTail(expr, parent)) { if (auto *UME = getUnresolvedMemberChainBase(expr)) { + CG.setUnresolvedChainBase(expr, UME); if (!parent || !isa(parent)) { - CG.setUnresolvedChainBase(expr, UME); auto &context = CG.getConstraintSystem().getASTContext(); expr = new (context) UnresolvedMemberChainResultExpr(expr); } From ed941314fff2815621b96945b749d43000ec9bf1 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Tue, 4 Aug 2020 10:29:00 -0400 Subject: [PATCH 367/663] [Sema] Bail out early of solution application for UME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …when the deduced type is unresolved. Otherwise, we won’t be able to fetch the overload choice or do anything else useful. --- lib/Sema/CSApply.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 53afe327a3fd3..56f5154ebe4be 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2753,6 +2753,15 @@ namespace { } Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { + // If constraint solving resolved this to an UnresolvedType, then we're in + // an ambiguity tolerant mode used for diagnostic generation. Just leave + // this as an unresolved member reference. + Type resultTy = simplifyType(cs.getType(expr)); + if (resultTy->getRValueType()->is()) { + cs.setType(expr, resultTy); + return expr; + } + auto &ctx = cs.getASTContext(); // Find the selected member and base type. auto memberLocator = cs.getConstraintLocator( @@ -2762,6 +2771,7 @@ namespace { // Unresolved member lookup always happens in a metatype so dig out the // instance type. auto baseTy = selected.choice.getBaseType()->getMetatypeInstanceType(); + baseTy = simplifyType(baseTy); // The base expression is simply the metatype of the base type. // FIXME: This location info is bogus. @@ -2805,8 +2815,7 @@ namespace { diagnoseAmbiguousNominalMember(baseTy, result); } - return coerceToType(result, simplifyType(cs.getType(expr)), - cs.getConstraintLocator(expr)); + return coerceToType(result, resultTy, cs.getConstraintLocator(expr)); } /// Diagnose if the base type is optional, we're referring to a nominal From 26f0a805994bbcf3d65904860a72f9a336df8976 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Tue, 4 Aug 2020 10:30:40 -0400 Subject: [PATCH 368/663] [Sema] Transfer contextual type info when we inject UnresolvedMemberChainResultExpr If we create an UnresolvedMemberChainResultExpr at the top level, we may end up losing contextual type information that was already attached to the end of the chain. To avoid this, we fetch any existing contextual type info and transfer it to the newly injected expression. --- lib/Sema/CSGen.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0ddb8919ed0bf..b2537c17eeaa3 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3847,8 +3847,14 @@ namespace { if (auto *UME = getUnresolvedMemberChainBase(expr)) { CG.setUnresolvedChainBase(expr, UME); if (!parent || !isa(parent)) { - auto &context = CG.getConstraintSystem().getASTContext(); + auto &cs = CG.getConstraintSystem(); + auto &context = cs.getASTContext(); + auto typeInfo = cs.getContextualTypeInfo(expr); expr = new (context) UnresolvedMemberChainResultExpr(expr); + if (typeInfo) { + cs.setContextualType(expr, (*typeInfo).typeLoc, + (*typeInfo).purpose); + } } } } From 74d004057e868d9e25071fa4b613a4d1b1c46245 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Tue, 4 Aug 2020 15:08:28 -0400 Subject: [PATCH 369/663] [Sema] Remove unnecessary impact adjustment --- lib/Sema/CSSimplify.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index d24656ca0497e..e051d9934bd2a 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -10060,12 +10060,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( impact = 10; } - if (locator->isLastElement()) { - // If this is a contextual failure for an unresolved member, then increase - // the impact to attempt other fixes first and avoid ambiguity. - impact = 2; - } - if (recordFix(fix, impact)) return SolutionKind::Error; From 189235678f0f007369d4207adbd0686f28832b9c Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Tue, 4 Aug 2020 18:43:38 -0400 Subject: [PATCH 370/663] [Sema] Move member chain transformation into precheck Move the analysis and transformation of unresolved member chains into the PreCheckExpression pass in order to make sure that contextual types get hooked up properly before we actually begin generating constraints. --- lib/Sema/CSDiagnostics.cpp | 10 +++- lib/Sema/CSGen.cpp | 76 +------------------------------ lib/Sema/TypeCheckConstraints.cpp | 46 +++++++++++++++++++ lib/Sema/TypeChecker.h | 5 ++ 4 files changed, 61 insertions(+), 76 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 5b1049b46e067..17e88bbf957e8 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1131,6 +1131,8 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt( bool needsParensInside = exprNeedsParensBeforeAddingNilCoalescing(DC, const_cast(expr)); auto parentExpr = findParentExpr(anchor); + if (parentExpr && isa(parentExpr)) + parentExpr = findParentExpr(parentExpr); bool needsParensOutside = exprNeedsParensAfterAddingNilCoalescing( DC, const_cast(expr), parentExpr); @@ -6325,6 +6327,12 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { // Member reference could be wrapped into a number of parens // e.g. `((.foo))`. auto *parentExpr = findParentExpr(anchor); + UnresolvedMemberChainResultExpr *resultExpr = nullptr; + if (parentExpr && isa(parentExpr)) { + resultExpr = cast(parentExpr); + parentExpr = findParentExpr(parentExpr); + } + do { // If we have found something which isn't a paren let's stop, // otherwise let's keep unwrapping until there are either no @@ -6333,7 +6341,7 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { break; } while ((parentExpr = findParentExpr(parentExpr))); - auto diagnostic = parentExpr || getContextualType(anchor) + auto diagnostic = parentExpr || (resultExpr && getContextualType(resultExpr)) ? diag::cannot_infer_base_of_unresolved_member : diag::unresolved_member_no_inference; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index b2537c17eeaa3..a94584d47f506 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -74,46 +74,6 @@ static bool mergeRepresentativeEquivalenceClasses(ConstraintSystem &CS, return false; } -/// Find the next element in a chain of members. If this expression is (or -/// could be) the base of such a chain, this will return \c nullptr. -static Expr *getMemberChainSubExpr(Expr *expr) { - assert(expr && "getMemberChainSubExpr called with null expr!"); - if (auto *UDE = dyn_cast(expr)) { - return UDE->getBase(); - } else if (auto *CE = dyn_cast(expr)) { - return CE->getFn(); - } else if (auto *BOE = dyn_cast(expr)) { - return BOE->getSubExpr(); - } else if (auto *FVE = dyn_cast(expr)) { - return FVE->getSubExpr(); - } else if (auto *SE = dyn_cast(expr)) { - return SE->getBase(); - } else { - return nullptr; - } -} - -/// Returns the base of a chain of member accesses/method calls. Most -/// expressions do not participate in member chains, and just return \c this. -static UnresolvedMemberExpr *getUnresolvedMemberChainBase(Expr *expr) { - if (auto *subExpr = getMemberChainSubExpr(expr)) - return getUnresolvedMemberChainBase(subExpr); - else - return dyn_cast(expr); -} - -/// Whether this expression is a member of a member chain. -static bool isMemberChainMember(Expr *expr) { - return getMemberChainSubExpr(expr) != nullptr; -} -/// Whether this expression sits at the end of a chain of member accesses. -static bool isMemberChainTail(Expr *expr, Expr *parent) { - assert(expr && "isMemberChainTail called with null expr!"); - // If this expression's parent is not itself part of a chain (or, this expr - // has no parent expr), this must be the tail of the chain. - return parent == nullptr || !isMemberChainMember(parent); -} - namespace { /// Internal struct for tracking information about types within a series @@ -836,10 +796,6 @@ namespace { /// found during our walk. llvm::MapVector UnresolvedBaseTypes; - /// A map from the tail of each unresolved member chain to the respective - /// base of the chain. - llvm::MapVectorUnresolvedChainBases; - /// Returns false and emits the specified diagnostic if the member reference /// base is a nil literal. Returns true otherwise. bool isValidBaseOfMemberRef(Expr *base, Diag<> diagnostic) { @@ -1480,16 +1436,6 @@ namespace { assert(result != UnresolvedBaseTypes.end()); return result->second; } - - void setUnresolvedChainBase(Expr *tail, UnresolvedMemberExpr *base) { - UnresolvedChainBases.insert({tail, base}); - } - - UnresolvedMemberExpr *getUnresolvedChainBase(Expr *tail) { - auto result = UnresolvedChainBases.find(tail); - assert(result != UnresolvedChainBases.end()); - return result->second; - } virtual Type visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { auto baseLocator = CS.getConstraintLocator( @@ -1564,7 +1510,7 @@ namespace { "Unexpected expression at end of unresolved member chain"); auto memberTy = CS.getType(tail); - auto *base = getUnresolvedChainBase(tail); + auto *base = TypeChecker::getUnresolvedMemberChainBase(tail); // Copy any type variable options from the result of the tail member to // the result of the entire chain. @@ -3839,26 +3785,6 @@ namespace { if (auto *assignment = dyn_cast(expr)) CG.markAcceptableDiscardExprs(assignment->getDest()); - // If we find an unresolved member chain, wrap it in an - // UnresolvedMemberChainResultExpr (unless this has already been done) - // and generate constraints for the wrapped expression. - auto *parent = Parent.getAsExpr(); - if (isMemberChainTail(expr, parent)) { - if (auto *UME = getUnresolvedMemberChainBase(expr)) { - CG.setUnresolvedChainBase(expr, UME); - if (!parent || !isa(parent)) { - auto &cs = CG.getConstraintSystem(); - auto &context = cs.getASTContext(); - auto typeInfo = cs.getContextualTypeInfo(expr); - expr = new (context) UnresolvedMemberChainResultExpr(expr); - if (typeInfo) { - cs.setContextualType(expr, (*typeInfo).typeLoc, - (*typeInfo).purpose); - } - } - } - } - return { true, expr }; } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7eb6616d9a7d4..45fcb5f00dc24 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -477,6 +477,44 @@ static bool findNonMembers(ArrayRef lookupResults, return AllDeclRefs; } +/// Find the next element in a chain of members. If this expression is (or +/// could be) the base of such a chain, this will return \c nullptr. +static Expr *getMemberChainSubExpr(Expr *expr) { + assert(expr && "getMemberChainSubExpr called with null expr!"); + if (auto *UDE = dyn_cast(expr)) { + return UDE->getBase(); + } else if (auto *CE = dyn_cast(expr)) { + return CE->getFn(); + } else if (auto *BOE = dyn_cast(expr)) { + return BOE->getSubExpr(); + } else if (auto *FVE = dyn_cast(expr)) { + return FVE->getSubExpr(); + } else if (auto *SE = dyn_cast(expr)) { + return SE->getBase(); + } else { + return nullptr; + } +} + +UnresolvedMemberExpr *TypeChecker::getUnresolvedMemberChainBase(Expr *expr) { + if (auto *subExpr = getMemberChainSubExpr(expr)) + return getUnresolvedMemberChainBase(subExpr); + else + return dyn_cast(expr); +} + +/// Whether this expression is a member of a member chain. +static bool isMemberChainMember(Expr *expr) { + return getMemberChainSubExpr(expr) != nullptr; +} +/// Whether this expression sits at the end of a chain of member accesses. +static bool isMemberChainTail(Expr *expr, Expr *parent) { + assert(expr && "isMemberChainTail called with null expr!"); + // If this expression's parent is not itself part of a chain (or, this expr + // has no parent expr), this must be the tail of the chain. + return parent == nullptr || !isMemberChainMember(parent); +} + /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used /// for the lookup. @@ -1326,6 +1364,14 @@ namespace { if (auto *simplified = simplifyTypeConstructionWithLiteralArg(expr)) return simplified; + // If we find an unresolved member chain, wrap it in an + // UnresolvedMemberChainResultExpr (unless this has already been done). + auto *parent = Parent.getAsExpr(); + if (isMemberChainTail(expr, parent)) + if (auto *UME = TypeChecker::getUnresolvedMemberChainBase(expr)) + if (!parent || !isa(parent)) + return new (ctx) UnresolvedMemberChainResultExpr(expr); + return expr; } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 06e0786c18383..ddc5711d4ed5e 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1207,6 +1207,11 @@ bool requirePointerArgumentIntrinsics(ASTContext &ctx, SourceLoc loc); /// Require that the library intrinsics for creating /// array literals exist. bool requireArrayLiteralIntrinsics(ASTContext &ctx, SourceLoc loc); + +/// Gets the \c UnresolvedMemberExpr at the base of a chain of member accesses. +/// If \c expr is not part of a member chain or the base is something other than +/// an \c UnresolvedMemberExpr, \c nullptr is returned. +UnresolvedMemberExpr *getUnresolvedMemberChainBase(Expr *expr); }; // namespace TypeChecker /// Temporary on-stack storage and unescaping for encoded diagnostic From 7b05352cf1715d1c4b79de6a2585ddc34c056d66 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Wed, 5 Aug 2020 11:42:04 -0400 Subject: [PATCH 371/663] [Sema] Improve invalid lvalue diagnostics for UnresolvedMemberExpr We previously were not properly handling the diagnostics for using an rvalue implicit member on the left hand side of an assignment. This adds the proper handling and extends it for member chains. --- lib/Sema/CSDiagnostics.cpp | 22 +++++++++++++++++++++ lib/Sema/CSSimplify.cpp | 3 +++ test/expr/delayed-ident/member_chains.swift | 20 ++++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 17e88bbf957e8..1abc4d61e6d6a 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1314,6 +1314,11 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { if (getContextualTypePurpose(diagExpr) == CTP_Condition) return false; + // If the failure happened at the end of an unresolved member chain, it should + // be diagnosed instead as though it happened at the last element. + if (auto chainExpr = dyn_cast(diagExpr)) + diagExpr = chainExpr->getSubExpr(); + if (auto assignExpr = dyn_cast(diagExpr)) { // Let's check whether this is an attempt to assign // variable or property to itself. @@ -1437,6 +1442,11 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { } } else if (isa(diagExpr)) { subElementDiagID = diag::assignment_subscript_has_immutable_base; + } else if (auto *UME = dyn_cast(diagExpr)) { + if (UME->hasArguments()) + subElementDiagID = diag::assignment_lhs_is_apply_expression; + else + subElementDiagID = diag::assignment_lhs_is_immutable_property; } else { subElementDiagID = diag::assignment_lhs_is_immutable_variable; } @@ -1903,6 +1913,18 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { return resolveImmutableBase(MRE->getBase()); } + if (auto *UME = dyn_cast(expr)) { + auto loc = getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); + auto member = getMemberRef(loc); + + // If we can resolve a member, we can determine whether it is settable in + // this context. + if (member && member->isDecl() && isImmutable(member->getDecl())) + return {expr, member}; + else + return {expr, None}; + } + if (auto *DRE = dyn_cast(expr)) return {expr, OverloadChoice(Type(), DRE->getDecl(), FunctionRefKind::Unapplied)}; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index e051d9934bd2a..b252b1773756f 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4314,6 +4314,9 @@ bool ConstraintSystem::repairFailures( locator)) break; + if (repairByTreatingRValueAsLValue(lhs, rhs)) + break; + // If there is a type mismatch here it's contextual e.g., // `let x: E = .foo(42)`, where `.foo` is a member of `E` // but produces an incorrect type. diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index 7077c37e2ee87..27d84ea831abb 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -15,6 +15,8 @@ struct ImplicitMembers: Equatable { } static var implicit = ImplicitMembers() + static let implicitLet = ImplicitMembers() // expected-note2 {{change 'let' to 'var' to make it mutable}} + static var implicitImmutable: ImplicitMembers { ImplicitMembers() } static func createImplicit() -> ImplicitMembers { ImplicitMembers() } @@ -61,6 +63,7 @@ struct ImplicitMembers: Equatable { get { ImplicitMembers() } set {} } + subscript(immutable arg: Void) -> ImplicitMembers { ImplicitMembers() } subscript(func arg: Void) -> (() -> ImplicitMembers) { { ImplicitMembers() } } subscript(funcOptional arg: Void) -> (() -> ImplicitMembers?) { { ImplicitMembers() } } subscript(optionalFunc arg: Void) -> (() -> ImplicitMembers)? { { ImplicitMembers() } } @@ -205,7 +208,22 @@ func testLValues() { .implicit.anotherOptionalMutable! = local; .implicit[()] = local; .implicit[()].anotherMutable = local; - .optional?[optional: ()]?.anotherOptionalMutable! = local + .optional?[optional: ()]?.anotherOptionalMutable! = local; + + .implicitLet = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} + .implicitImmutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} + .createImplicit() = local; // expected-error {{cannot assign to value: 'createImplicit' is a method}} + .implicit.another = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} + .implicit[immutable: ()] = local; // expected-error {{cannot assign through subscript: subscript is get-only}} + .implicit.getAnother() = local; // expected-error {{expression is not assignable: function call returns immutable value}} + + .implicitLet.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} + .implicitImmutable.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} + .createImplicit().anotherMutable = local; // expected-error {{cannot assign to value: 'createImplicit' is a method}} + .implicit.another.anotherMutable = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} + .implicit[immutable: ()].anotherMutable = local; // expected-error {{cannot assign to property: subscript is get-only}} + .implicit.getAnother().anotherMutable = local; // expected-error {{cannot assign to property: function call returns immutable value}} + // FIXME: These should probably be allowed //.implicit.anotherOptionalMutable = local; From 00555016704211e6d7ba7f12e675974f551b561c Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Thu, 6 Aug 2020 15:44:25 -0400 Subject: [PATCH 372/663] [Sema] Add FIXME for Optional binding inference bug --- lib/Sema/CSGen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index a94584d47f506..7804cd6c7fe4b 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1512,6 +1512,7 @@ namespace { auto memberTy = CS.getType(tail); auto *base = TypeChecker::getUnresolvedMemberChainBase(tail); + // FIXME: This is a workaround for SR-13357, should not be necessary. // Copy any type variable options from the result of the tail member to // the result of the entire chain. unsigned additionalOptions = 0; From 5de23f5cfc9d462b59095fb6ede9f6aa4744cb04 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Wed, 12 Aug 2020 17:00:07 -0400 Subject: [PATCH 373/663] [Sema] Rebase and address feedback for implicit member chains --- include/swift/AST/DiagnosticsSema.def | 6 ++-- include/swift/AST/Expr.h | 12 ++++++-- lib/Sema/CSApply.cpp | 2 +- lib/Sema/CSDiagnostics.cpp | 14 ++-------- lib/Sema/CSGen.cpp | 31 ++++++--------------- lib/Sema/ConstraintSystem.cpp | 2 +- lib/Sema/TypeCheckConstraints.cpp | 2 +- test/expr/delayed-ident/member_chains.swift | 4 +-- 8 files changed, 31 insertions(+), 42 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index e2176f6bd6c26..55e30d4d1b338 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -113,7 +113,8 @@ ERROR(expected_argument_in_contextual_member,none, ERROR(expected_parens_in_contextual_member,none, "member %0 is a function; did you mean to call it?", (DeclName)) ERROR(expected_parens_in_contextual_member_type,none, - "member %0 is a function that produces expected type %1; did you mean to call it?", (DeclName, Type)) + "member %0 is a function that produces expected type %1; did you mean to " + "call it?", (DeclName, Type)) ERROR(expected_result_in_contextual_member,none, "member %0 in %2 produces result of type %1, but context expects %2", @@ -456,7 +457,8 @@ ERROR(cannot_convert_parent_type,none, "cannot convert parent type %0 to expected type %1", (Type, Type)) ERROR(cannot_convert_chain_result_type,none, - "member chain produces result of type %0 but contextual base was inferred as %1", + "member chain produces result of type %0 but contextual base was " + "inferred as %1", (Type, Type)) NOTE(generic_argument_mismatch,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 7ce334aba0771..d292a00d17fbf 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2094,10 +2094,18 @@ class ParenExpr : public IdentityExpr { /// to give the result type of such a chain representation in the AST. This /// expression type is always implicit. class UnresolvedMemberChainResultExpr : public IdentityExpr { + /// The base of this chain of member accesses. + UnresolvedMemberExpr *ChainBase; public: - UnresolvedMemberChainResultExpr(Expr *subExpr, Type ty = Type()) + UnresolvedMemberChainResultExpr(Expr *subExpr, UnresolvedMemberExpr *base, + Type ty = Type()) : IdentityExpr(ExprKind::UnresolvedMemberChainResult, subExpr, ty, - /*isImplicit=*/true) {} + /*isImplicit=*/true), + ChainBase(base) { + assert(base); + } + + UnresolvedMemberExpr *getChainBase() const { return ChainBase; } SWIFT_FORWARD_SOURCE_LOCS_TO(getSubExpr()) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 56f5154ebe4be..bcbb363713730 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2757,7 +2757,7 @@ namespace { // an ambiguity tolerant mode used for diagnostic generation. Just leave // this as an unresolved member reference. Type resultTy = simplifyType(cs.getType(expr)); - if (resultTy->getRValueType()->is()) { + if (resultTy->hasUnresolvedType()) { cs.setType(expr, resultTy); return expr; } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 1abc4d61e6d6a..066da31ad5341 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2160,17 +2160,9 @@ bool ContextualFailure::diagnoseAsError() { case ConstraintLocator::UnresolvedMemberChainResult: { auto &solution = getSolution(); - auto member = anchor; - if (auto *CE = getAsExpr(anchor)) - member = CE->getFn(); - - auto kind = ConstraintLocator::Member; - if (isExpr(anchor)) - kind = ConstraintLocator::UnresolvedMember; - else if (isExpr(anchor)) - kind = ConstraintLocator::SubscriptMember; - auto overload = getOverloadChoiceIfAvailable(getConstraintLocator(member, - kind)); + + auto overload = + getCalleeOverloadChoiceIfAvailable(getConstraintLocator(anchor)); if (!(overload && overload->choice.isDecl())) return false; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 7804cd6c7fe4b..f03ec3297463a 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1503,32 +1503,20 @@ namespace { Type visitUnresolvedMemberChainResultExpr( UnresolvedMemberChainResultExpr *expr) { auto *tail = expr->getSubExpr(); - assert(isa(tail) || isa(tail) || - isa(tail) || isa(tail) || - isa(tail) || - isa(tail) && - "Unexpected expression at end of unresolved member chain"); - auto memberTy = CS.getType(tail); - auto *base = TypeChecker::getUnresolvedMemberChainBase(tail); - - // FIXME: This is a workaround for SR-13357, should not be necessary. - // Copy any type variable options from the result of the tail member to - // the result of the entire chain. - unsigned additionalOptions = 0; - if (auto *tvt = memberTy->getAs()) - additionalOptions = tvt->getImpl().getRawOptions(); + auto *base = expr->getChainBase(); + assert(base == TypeChecker::getUnresolvedMemberChainBase(tail)); - // The contextual type (represented with a new type variable) must equal - // the base type. + // The result type of the chain is is represented by a new type variable. auto locator = CS.getConstraintLocator( expr, ConstraintLocator::UnresolvedMemberChainResult); - auto tvo = additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape; - auto chainResultTy = CS.createTypeVariable(locator, tvo); - auto chainBaseTy = UnresolvedBaseTypes.find(base)->second; + auto chainResultTy = CS.createTypeVariable( + locator, + TVO_CanBindToLValue | TVO_CanBindToHole | TVO_CanBindToNoEscape); + auto chainBaseTy = getUnresolvedBaseType(base); - // The result of this element of the chain must be convertible to the - // contextual type, and the contextual type must be equal to the base. + // The result of the last element of the chain must be convertible to the + // whole chain, and the type of the whole chain must be equal to the base. CS.addConstraint( ConstraintKind::Conversion, memberTy, chainBaseTy, CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); @@ -3828,7 +3816,6 @@ namespace { } if (auto type = CG.visit(expr)) { - auto simplifiedType = CS.simplifyType(type); CS.setType(expr, simplifiedType); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index dad11b3fd25ea..a933da4a6857c 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3860,7 +3860,7 @@ void constraints::simplifyLocator(ASTNode &anchor, } case ConstraintLocator::UnresolvedMemberChainResult: { - auto *resultExpr = getAsExpr(anchor); + auto *resultExpr = castToExpr(anchor); anchor = resultExpr->getSubExpr(); path = path.slice(1); continue; diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 45fcb5f00dc24..44bf6e22cba96 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -1370,7 +1370,7 @@ namespace { if (isMemberChainTail(expr, parent)) if (auto *UME = TypeChecker::getUnresolvedMemberChainBase(expr)) if (!parent || !isa(parent)) - return new (ctx) UnresolvedMemberChainResultExpr(expr); + return new (ctx) UnresolvedMemberChainResultExpr(expr, UME); return expr; } diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index 27d84ea831abb..ed694ab8ad98c 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -126,8 +126,8 @@ let _: ImplicitMembers = .implicit[optional: ()] // expected-error {{value of op let _: ImplicitMembers = .implicit[funcOptional: ()]() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{55-55= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{55-55=!}} // FIXME: Improve these diagnostics (should probably offer unwrapping, as above) -let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error{{cannot infer contextual base in reference to member 'implicit'}} expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}} -let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{cannot infer contextual base in reference to member 'implicit'}} expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error{{type of expression is ambiguous without more context}} +let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{type of expression is ambiguous without more context}} let _: ImplicitMembers = .other.implicit From 968112e420eea7d7f028456c8a873141d6b2c6ba Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Sun, 16 Aug 2020 23:15:01 -0400 Subject: [PATCH 374/663] [Sema] Support code completion for heterogeneous unresolved member chains --- lib/Sema/TypeCheckConstraints.cpp | 2 + test/IDE/complete_unresolved_chains.swift | 79 +++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 test/IDE/complete_unresolved_chains.swift diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 44bf6e22cba96..5c16de3953a8c 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -491,6 +491,8 @@ static Expr *getMemberChainSubExpr(Expr *expr) { return FVE->getSubExpr(); } else if (auto *SE = dyn_cast(expr)) { return SE->getBase(); + } else if (auto *CCE = dyn_cast(expr)) { + return CCE->getBase(); } else { return nullptr; } diff --git a/test/IDE/complete_unresolved_chains.swift b/test/IDE/complete_unresolved_chains.swift new file mode 100644 index 0000000000000..bd89f737905a8 --- /dev/null +++ b/test/IDE/complete_unresolved_chains.swift @@ -0,0 +1,79 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_1 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_2 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_3 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_4 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_5 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_2 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_6 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_7 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DOUBLY_NESTED| %FileCheck %s -check-prefix=DOUBLY_NESTED + +struct ChainStruct1 { + static var chain2 = ChainStruct2() + static func chain2Func() -> ChainStruct2 { ChainStruct2() } +} + +struct ChainStruct2 { + var chainStruct1 = ChainStruct1() + var chainEnum = ChainEnum.case1 + var chainStruct2: ChainStruct2 { ChainStruct2() } + func chainStruct1Func() -> ChainStruct1 { ChainStruct1() } +} + +enum ChainEnum { + case case1 + var chainStruct2: ChainStruct2 { ChainStruct2() } + func chainStruct2Func() -> ChainStruct2 { ChainStruct2() } +} + +func testChains() { + let _: ChainStruct1 = .chain2.#^UNRESOLVED_CHAIN_1^# + let _: ChainStruct1 = .chain2.chainStruct2.#^UNRESOLVED_CHAIN_2^# + let _: ChainStruct1 = .chain2Func().#^UNRESOLVED_CHAIN_3^# + let _: ChainStruct1 = .chain2Func().#^UNRESOLVED_CHAIN_4^# + let _: ChainEnum = .case1.#^UNRESOLVED_CHAIN_5^# + let _: ChainEnum = .case1.chainStruct2.#^UNRESOLVED_CHAIN_6^# + let _: ChainEnum = .case1.chainStruct2.#^UNRESOLVED_CHAIN_7^# +} + +// UNRESOLVED_CHAIN_1: Begin completions, 5 items +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: chainStruct1[#ChainStruct1#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainEnum[#ChainEnum#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: chainStruct1Func()[#ChainStruct1#]; +// UNRESOLVED_CHAIN_1: End completions + +// UNRESOLVED_CHAIN_2: Begin completions, 5 items +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; +// UNRESOLVED_CHAIN_2: End completions + +// UNRESOLVED_CHAIN_3: Begin completions, 5 items +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal: chainStruct1[#ChainStruct1#]; name=chainStruct1 +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: chainEnum[#ChainEnum#]; name=chainEnum +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; name=chainStruct2 +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceMethod]/CurrNominal: chainStruct1Func()[#ChainStruct1#]; name=chainStruct1Func() +// UNRESOLVED_CHAIN_3: End completions + +class Outer { + class Inner: Outer { + class InnerInner: Inner {} + static var outer = Outer() + static var inner = Inner() + static func makeOuter() -> Outer { Outer() } + static func makeInner() -> Inner { Inner() } + } +} + +func testDoublyNestedType() { + let _: Outer = .Inner.#^DOUBLY_NESTED^# +} + +// DOUBLY_NESTED: Begin completions, 8 items +// DOUBLY_NESTED-DAG: Decl[Class]/CurrNominal/TypeRelation[Convertible]: InnerInner[#Outer.Inner.InnerInner#]; +// DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: outer[#Outer#]; +// DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: inner[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: makeOuter()[#Outer#]; +// DOUBLY_NESTED-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: makeInner()[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[Class]/Super/TypeRelation[Convertible]: Inner[#Outer.Inner#]; +// DOUBLY_NESTED: End completions + From db33dfa3a110aa6d6dde0c5176b2d8d89afe243c Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Thu, 20 Aug 2020 22:24:53 -0400 Subject: [PATCH 375/663] [IDE] Offer unresolved member completions with non-matching types Since the user can now write additional member accesses off of an UnresolvedMemberExpr, we should offer all available completions rather than just those that match the contextual type. --- lib/IDE/CodeCompletion.cpp | 10 ++- test/IDE/complete_annotation.swift | 6 +- test/IDE/complete_assignment.swift | 6 +- test/IDE/complete_call_arg.swift | 10 ++- test/IDE/complete_call_as_function.swift | 4 +- test/IDE/complete_constrained.swift | 4 +- test/IDE/complete_enum_elements.swift | 22 +++++- ...complete_property_delegate_attribute.swift | 3 +- test/IDE/complete_stmt_controlling_expr.swift | 8 ++- test/IDE/complete_string_interpolation.swift | 6 +- test/IDE/complete_unresolved_chains.swift | 8 ++- test/IDE/complete_unresolved_members.swift | 67 +++++++++++++------ 12 files changed, 115 insertions(+), 39 deletions(-) diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 4d14814a55103..bd5c98c9a4e20 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -4284,14 +4284,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (!T->mayHaveMembers()) return; - DeclContext *DC = const_cast(CurrDeclContext); - // We can only say .foo where foo is a static member of the contextual // type and has the same type (or if the member is a function, then the // same result type) as the contextual type. FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind Reason) { - return isReferenceableByImplicitMemberExpr(CurrModule, DC, T, VD); + if (T->getOptionalObjectType() && + VD->getModuleContext()->isStdlibModule()) { + // In optional context, ignore '.init()', 'init(nilLiteral:)', + if (isa(VD)) + return false; + } + return true; }); auto baseType = MetatypeType::get(T); diff --git a/test/IDE/complete_annotation.swift b/test/IDE/complete_annotation.swift index d9dde1ac6c8e5..0e267618ca87a 100644 --- a/test/IDE/complete_annotation.swift +++ b/test/IDE/complete_annotation.swift @@ -95,9 +95,13 @@ func testPostfix(value: MyStruct) { func testImplicitMember() -> MyStruct { return .#^EXPR_IMPLICITMEMBER^# } -// EXPR_IMPLICITMEMBER: Begin completions, 3 items +// EXPR_IMPLICITMEMBER: Begin completions, 7 items // EXPR_IMPLICITMEMBER-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init(x: Int); typename=MyStruct; // EXPR_IMPLICITMEMBER-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: instance; typename=MyStruct; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: labelNameParamName(_ self: MyStruct); typename=(label: (inout Int) throws -> MyStruct) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: labelName(_ self: MyStruct); typename=(label: (@autoclosure () -> Int) -> Int) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: sameName(_ self: MyStruct); typename=(label: inout Int) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: paramName(_ self: MyStruct); typename=(Int) -> Void; // EXPR_IMPLICITMEMBER-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: create(x: Int); typename=MyStruct; // EXPR_IMPLICITMEMBER: End completions diff --git a/test/IDE/complete_assignment.swift b/test/IDE/complete_assignment.swift index 3fa5753e0b30c..871ef3db1dd2c 100644 --- a/test/IDE/complete_assignment.swift +++ b/test/IDE/complete_assignment.swift @@ -127,17 +127,19 @@ func f2() { d = .#^ASSIGN_5^# } -// ASSIGN_5: Begin completions, 2 items +// ASSIGN_5: Begin completions, 3 items // ASSIGN_5-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case2[#D1#]; name=case2 // ASSIGN_5-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case1[#D1#]; name=case1 +// ASSIGN_5-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): D1#})[#(into: inout Hasher) -> Void#]; name=hash(self: D1) func f6() { var d : D2 d = .#^ASSIGN_6^# } -// ASSIGN_6: Begin completions, 2 items +// ASSIGN_6: Begin completions, 3 items // ASSIGN_6-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case3[#D2#]; name=case3 // ASSIGN_6-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case4[#D2#]; name=case4 +// ASSIGN_6-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): D2#})[#(into: inout Hasher) -> Void#]; name=hash(self: D2) func f7 (C : C2) { var i : Int diff --git a/test/IDE/complete_call_arg.swift b/test/IDE/complete_call_arg.swift index 978810776e125..07e5d183f7b62 100644 --- a/test/IDE/complete_call_arg.swift +++ b/test/IDE/complete_call_arg.swift @@ -579,10 +579,12 @@ func testTupleShuffle() { // SHUFFLE_2-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s1[#String#]; name=s1 // SHUFFLE_2-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s2[#String#]; name=s2 -// SHUFFLE_3: Begin completions, 3 items +// SHUFFLE_3: Begin completions, 4 items // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// SHUFFLE_3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) + class HasSubscript { subscript(idx: Int) -> String {} @@ -833,10 +835,11 @@ func testPamrameterFlags(_: Int, inoutArg: inout Int, autoclosureArg: @autoclosu func testTupleElement(arg: (SimpleEnum, SimpleEnum)) { testTupleElement(arg: (.foo, .#^TUPLEELEM_1^#)) -// TUPLEELEM_1: Begin completions, 3 items +// TUPLEELEM_1: Begin completions, 4 items // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// TUPLEELEM_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) // TUPLEELEM_1: End completions testTupleElement(arg: (.foo, .bar, .#^TUPLEELEM_2^#)) // TUPLEELEM_2-NOT: Begin completions @@ -852,10 +855,11 @@ func testKeyPathThunkInBase() { func foo(_ fn: (TestKP) -> Int) -> TestKPResult { TestKPResult() } foo(\.value).testFunc(.#^KEYPATH_THUNK_BASE^#) -// KEYPATH_THUNK_BASE: Begin completions, 3 items +// KEYPATH_THUNK_BASE: Begin completions, 4 items // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// KEYPATH_THUNK_BASE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) // KEYPATH_THUNK_BASE: End completions } diff --git a/test/IDE/complete_call_as_function.swift b/test/IDE/complete_call_as_function.swift index 836b3a9a7d84e..ebd371b95312c 100644 --- a/test/IDE/complete_call_as_function.swift +++ b/test/IDE/complete_call_as_function.swift @@ -111,10 +111,12 @@ func testCallAsFunctionOverloaded(fn: Functor) { fn(h: .left, v: .#^OVERLOADED_ARG2_VALUE^#) // FIXME: Should only suggest 'up' and 'down' (rdar://problem/60346573). -//OVERLOADED_ARG2_VALUE: Begin completions, 4 items +//OVERLOADED_ARG2_VALUE: Begin completions, 6 items //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: up[#Functor.Vertical#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: down[#Functor.Vertical#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Functor.Vertical#})[#(into: inout Hasher) -> Void#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: left[#Functor.Horizontal#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: right[#Functor.Horizontal#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Functor.Horizontal#})[#(into: inout Hasher) -> Void#]; //OVERLOADED_ARG2_VALUE: End completions } diff --git a/test/IDE/complete_constrained.swift b/test/IDE/complete_constrained.swift index bb85a6c711c02..cc655f4af2ea2 100644 --- a/test/IDE/complete_constrained.swift +++ b/test/IDE/complete_constrained.swift @@ -117,9 +117,11 @@ struct Vegetarian: EatsFruit, EatsVegetables { } func testVegetarian(chef: Chef) { chef.cook(.#^CONDITIONAL_OVERLOAD_ARG^#) -// CONDITIONAL_OVERLOAD_ARG: Begin completions, 2 items +// CONDITIONAL_OVERLOAD_ARG: Begin completions, 4 items // CONDITIONAL_OVERLOAD_ARG-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: apple[#Fruit#]; name=apple +// CONDITIONAL_OVERLOAD_ARG-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Fruit#})[#(into: inout Hasher) -> Void#]; name=hash(self: Fruit) // CONDITIONAL_OVERLOAD_ARG-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: broccoli[#Vegetable#]; name=broccoli +// CONDITIONAL_OVERLOAD_ARG-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Vegetable#})[#(into: inout Hasher) -> Void#]; name=hash(self: Vegetable) // CONDITIONAL_OVERLOAD_ARG: End completions var chefMeta: Chef.Type = Chef.self diff --git a/test/IDE/complete_enum_elements.swift b/test/IDE/complete_enum_elements.swift index 7f4097efb0a9c..533fd73ce6515 100644 --- a/test/IDE/complete_enum_elements.swift +++ b/test/IDE/complete_enum_elements.swift @@ -138,10 +138,18 @@ enum FooEnum: CaseIterable { // FOO_ENUM_DOT_INVALID-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}} // FOO_ENUM_DOT_INVALID-NEXT: End completions -// FOO_ENUM_DOT_ELEMENTS: Begin completions, 3 items +// FOO_ENUM_DOT_ELEMENTS: Begin completions, 11 items // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo1[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo2[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: alias1[#FooEnum#]; name=alias1 +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): FooEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: FooEnum) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#arrayLiteral: FooEnum...#})[#Array#]; name=AllCases(arrayLiteral: FooEnum...) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases()[#Array#]; name=AllCases() +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#(s): Sequence#})[#Array#]; name=AllCases(s: Sequence) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#repeating: FooEnum#}, {#count: Int#})[#Array#]; name=AllCases(repeating: FooEnum, count: Int) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#unsafeUninitializedCapacity: Int#}, {#initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void##(inout UnsafeMutableBufferPointer, inout Int) throws -> Void#})[' rethrows'][#Array#]; name=AllCases(unsafeUninitializedCapacity: Int, initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void) rethrows +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#from: Decoder#})[' throws'][#Array#]; name=AllCases(from: Decoder) throws +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]; name=allCases // FOO_ENUM_DOT_ELEMENTS-NEXT: End completions enum BarEnum { @@ -454,9 +462,19 @@ func testWithInvalid1() { func testUnqualified1(x: QuxEnum) { _ = x == .Qux1 || x == .#^UNRESOLVED_2^#Qux2 - // UNRESOLVED_2: Begin completions, 2 items + // UNRESOLVED_2: Begin completions, 12 items // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux1[#QuxEnum#]; name=Qux1 // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux2[#QuxEnum#]; name=Qux2 + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: UInt#})[#Int#]; name=RawValue(bitPattern: UInt) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#(source): Float#})[#Int#]; name=RawValue(source: Float) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#(source): Double#})[#Int#]; name=RawValue(source: Double) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#(source): Float80#})[#Int#]; name=RawValue(source: Float80) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#from: Decoder#})[' throws'][#Int#]; name=RawValue(from: Decoder) throws + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: OpaquePointer?#})[#Int#]; name=RawValue(bitPattern: OpaquePointer?) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: ObjectIdentifier#})[#Int#]; name=RawValue(bitPattern: ObjectIdentifier) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: _Pointer?#})[#Int#]; name=RawValue(bitPattern: _Pointer?) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal: init({#rawValue: Int#})[#QuxEnum?#]; name=init(rawValue: Int) + // UNRESOLVED_2-DAG: Decl[InstanceMethod]/Super/IsSystem/TypeRelation[Invalid]: hash({#(self): QuxEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: QuxEnum) // UNRESOLVED_2: End completions _ = (x == .Qux1#^UNRESOLVED_3^#) diff --git a/test/IDE/complete_property_delegate_attribute.swift b/test/IDE/complete_property_delegate_attribute.swift index 5cf00f41e1b1b..ba1de7930993d 100644 --- a/test/IDE/complete_property_delegate_attribute.swift +++ b/test/IDE/complete_property_delegate_attribute.swift @@ -34,9 +34,10 @@ struct TestStruct { @MyStruct(arg1: .#^ARG_MyEnum_DOT^# var test3 -// ARG_MyEnum_DOT: Begin completions, 2 items +// ARG_MyEnum_DOT: Begin completions, 3 items // ARG_MyEnum_DOT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: east[#MyEnum#]; name=east // ARG_MyEnum_DOT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: west[#MyEnum#]; name=west +// ARG_MyEnum_DOT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MyEnum#})[#(into: inout Hasher) -> Void#]; // ARG_MyEnum_DOT: End completions @MyStruct(arg1: MyEnum.#^ARG_MyEnum_NOBINDING^#) diff --git a/test/IDE/complete_stmt_controlling_expr.swift b/test/IDE/complete_stmt_controlling_expr.swift index b76a9bfad2f14..ccbabf4c8395f 100644 --- a/test/IDE/complete_stmt_controlling_expr.swift +++ b/test/IDE/complete_stmt_controlling_expr.swift @@ -644,11 +644,17 @@ func testGuardCase(x:FooStruct?) { // FOOSTRUCT_LOCALVAL-DAG: Decl[LocalVar]/Local{{(/TypeRelation\[Convertible\])?}}: boundVal[#FooStruct#]; // FOOSTRUCT_LOCALVAL: End completions -// OPTIONAL_FOOSTRUCT: Begin completions, 5 items +// OPTIONAL_FOOSTRUCT: Begin completions, 9 items // OPTIONAL_FOOSTRUCT-DAG: Keyword[nil]/None/Erase[1]: nil[#FooStruct?#]; name=nil // OPTIONAL_FOOSTRUCT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // OPTIONAL_FOOSTRUCT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#FooStruct#})[#Optional#]; name=some(FooStruct) // FIXME: 'FooStruct' members should not be shown. // OPTIONAL_FOOSTRUCT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#FooStruct#]; name=init() // OPTIONAL_FOOSTRUCT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init({#Int#})[#FooStruct#]; name=init(Int) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal: boolGen({#(self): FooStruct#})[#() -> Bool#]; name=boolGen(self: FooStruct) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal: intGen({#(self): FooStruct#})[#() -> Int#]; name=intGen(self: FooStruct) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((FooStruct) throws -> U) -> U?#]; name=map(self: Optional) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((FooStruct) throws -> U?) -> U?#]; name=flatMap(self: Optional) +// OPTIONAL_FOOSTRUCT-NOT: init({#(some): +// OPTIONAL_FOOSTRUCT-NOT: init({#nilLiteral: // OPTIONAL_FOOSTRUCT: End completions diff --git a/test/IDE/complete_string_interpolation.swift b/test/IDE/complete_string_interpolation.swift index 4187ca51cf480..1089516beb5f1 100644 --- a/test/IDE/complete_string_interpolation.swift +++ b/test/IDE/complete_string_interpolation.swift @@ -31,17 +31,19 @@ struct MsgInterpolation: StringInterpolationProtocol { var messenger = Messenger() func testMessenger(intVal: Int, fltVal: Float) { messenger.send(" \(intVal, format: .#^OVERLOAD_INT^#) ") -// OVERLOAD_INT: Begin completions, 4 items +// OVERLOAD_INT: Begin completions, 5 items // OVERLOAD_INT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: decimal[#MsgInterpolation.IntFormat#]; // OVERLOAD_INT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: hex[#MsgInterpolation.IntFormat#]; +// OVERLOAD_INT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MsgInterpolation.IntFormat#})[#(into: inout Hasher) -> Void#]; // OVERLOAD_INT-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: precision({#Int#})[#MsgInterpolation.FloatFormat#]; // OVERLOAD_INT-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: hex[#MsgInterpolation.FloatFormat#]; // OVERLOAD_INT: End completions messenger.send(" \(fltVal, format: .#^OVERLOAD_FLT^#) ") -// OVERLOAD_FLT: Begin completions, 4 items +// OVERLOAD_FLT: Begin completions, 5 items // OVERLOAD_FLT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: decimal[#MsgInterpolation.IntFormat#]; // OVERLOAD_FLT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: hex[#MsgInterpolation.IntFormat#]; +// OVERLOAD_FLT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MsgInterpolation.IntFormat#})[#(into: inout Hasher) -> Void#]; // OVERLOAD_FLT-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: precision({#Int#})[#MsgInterpolation.FloatFormat#]; // OVERLOAD_FLT-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: hex[#MsgInterpolation.FloatFormat#]; // OVERLOAD_FLT: End completions diff --git a/test/IDE/complete_unresolved_chains.swift b/test/IDE/complete_unresolved_chains.swift index bd89f737905a8..f1d2930ce7e17 100644 --- a/test/IDE/complete_unresolved_chains.swift +++ b/test/IDE/complete_unresolved_chains.swift @@ -36,6 +36,7 @@ func testChains() { } // UNRESOLVED_CHAIN_1: Begin completions, 5 items +// UNRESOLVED_CHAIN_1-DAG: Keyword[self]/CurrNominal: self[#ChainStruct2#]; name=self // UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: chainStruct1[#ChainStruct1#]; // UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainEnum[#ChainEnum#]; // UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; @@ -43,7 +44,11 @@ func testChains() { // UNRESOLVED_CHAIN_1: End completions // UNRESOLVED_CHAIN_2: Begin completions, 5 items -// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; +// UNRESOLVED_CHAIN_2-DAG: Keyword[self]/CurrNominal: self[#ChainEnum#]; name=self +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; name=chainStruct2 +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceMethod]/CurrNominal: chainStruct2Func()[#ChainStruct2#]; name=chainStruct2Func() +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: hashValue[#Int#]; name=hashValue +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#into: &Hasher#})[#Void#]; name=hash(into: &Hasher) // UNRESOLVED_CHAIN_2: End completions // UNRESOLVED_CHAIN_3: Begin completions, 5 items @@ -68,6 +73,7 @@ func testDoublyNestedType() { } // DOUBLY_NESTED: Begin completions, 8 items +// DOUBLY_NESTED-DAG: Keyword[self]/CurrNominal: self[#Outer.Inner.Type#]; name=self // DOUBLY_NESTED-DAG: Decl[Class]/CurrNominal/TypeRelation[Convertible]: InnerInner[#Outer.Inner.InnerInner#]; // DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: outer[#Outer#]; // DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: inner[#Outer.Inner#]; diff --git a/test/IDE/complete_unresolved_members.swift b/test/IDE/complete_unresolved_members.swift index 7a895c550c665..80d50f2c3e4f1 100644 --- a/test/IDE/complete_unresolved_members.swift +++ b/test/IDE/complete_unresolved_members.swift @@ -226,7 +226,8 @@ class C2 { // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option1[#SomeOptions1#]; name=Option1 // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option2[#SomeOptions1#]; name=Option2 // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option3[#SomeOptions1#]; name=Option3 -// UNRESOLVED_1-NOT: Not +// UNRESOLVED_1-DAG: Decl[StaticVar]/CurrNominal: NotOption[#Int#]; name=NotOption +// UNRESOLVED_1-NOT: NotStaticOption // UNRESOLVED_1_NOTIDEAL: Begin completions // UNRESOLVED_1_NOTIDEAL-NOT: SomeEnum1 @@ -234,7 +235,8 @@ class C2 { // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option1[#SomeOptions1#]; name=Option1 // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option2[#SomeOptions1#]; name=Option2 // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option3[#SomeOptions1#]; name=Option3 -// UNRESOLVED_1_NOTIDEAL-NOT: Not +// UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal: NotOption[#Int#]; name=NotOption +// UNRESOLVED_1_NOTIDEAL-NOT: NotStaticOption } class C3 { @@ -274,39 +276,49 @@ class C4 { var _: SomeEnum1??? = .#^UNRESOLVED_OPT_3^# } } -// UNRESOLVED_3: Begin completions, 2 items +// UNRESOLVED_3: Begin completions, 3 items // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: North[#SomeEnum1#]; name=North // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: South[#SomeEnum1#]; name=South +// UNRESOLVED_3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; name=hash(self: SomeEnum1) // UNRESOLVED_3-NOT: SomeOptions1 // UNRESOLVED_3-NOT: SomeOptions2 // UNRESOLVED_3-NOT: none // UNRESOLVED_3-NOT: some( -// UNRESOLVED_3_NOTIDEAL: Begin completions, 2 items +// UNRESOLVED_3_NOTIDEAL: Begin completions, 3 items // UNRESOLVED_3_NOTIDEAL-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; name=North // UNRESOLVED_3_NOTIDEAL-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; name=South +// UNRESOLVED_3_NOTIDEAL-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; name=hash(self: SomeEnum1) // UNRESOLVED_3_NOTIDEAL-NOT: SomeOptions1 // UNRESOLVED_3_NOTIDEAL-NOT: SomeOptions2 // UNRESOLVED_3_NOTIDEAL-NOT: none // UNRESOLVED_3_NOTIDEAL-NOT: some( -// UNRESOLVED_3_OPT: Begin completions, 5 items +// UNRESOLVED_3_OPT: Begin completions, 9 items // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: North[#SomeEnum1#]; // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: South[#SomeEnum1#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_3_OPT-DAG: Keyword[nil]/None/Erase[1]: nil[#SomeEnum1?#]; name=nil // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#SomeEnum1#})[#Optional#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((SomeEnum1) throws -> U) -> U?#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((SomeEnum1) throws -> U?) -> U?#]; // UNRESOLVED_3_OPT-NOT: init({#(some): // UNRESOLVED_3_OPT-NOT: init({#nilLiteral: +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; -// UNRESOLVED_3_OPTOPTOPT: Begin completions, 5 items +// UNRESOLVED_3_OPTOPTOPT: Begin completions, 9 items // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: North[#SomeEnum1#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: South[#SomeEnum1#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/None/Erase[1]: nil[#SomeEnum1???#]; name=nil // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#SomeEnum1??#})[#Optional#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((SomeEnum1??) throws -> U) -> U?#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((SomeEnum1??) throws -> U?) -> U?#]; // UNRESOLVED_3_OPTOPTOPT-NOT: init({#(some): // UNRESOLVED_3_OPTOPTOPT-NOT: init({#nilLiteral: +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; enum Somewhere { case earth, mars @@ -317,14 +329,18 @@ extension Optional where Wrapped == Somewhere { } func testOptionalWithCustomExtension() { var _: Somewhere? = .#^UNRESOLVED_OPT_4^# -// UNRESOLVED_OPT_4: Begin completions, 7 items +// UNRESOLVED_OPT_4: Begin completions, 11 items // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: earth[#Somewhere#]; // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: mars[#Somewhere#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Somewhere#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_OPT_4-DAG: Keyword[nil]/None/Erase[1]: nil[#Somewhere?#]; name=nil // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#Somewhere#})[#Optional#]; // UNRESOLVED_OPT_4-DAG: Decl[Constructor]/CurrNominal: init({#str: String#})[#Optional#]; name=init(str: String) // UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional#]; name=nowhere +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((Somewhere) throws -> U) -> U?#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((Somewhere) throws -> U?) -> U?#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_OPT_4-NOT: init({#(some): // UNRESOLVED_OPT_4-NOT: init({#nilLiteral: // UNRESOLVED_OPT_4: End completions @@ -433,10 +449,11 @@ let _: [SomeEnum3:SomeEnum1] = [.Payload(.South):.South, .Payload(.#^UNRESOLVED_ func testAvail1(_ x: EnumAvail1) { testAvail1(.#^ENUM_AVAIL_1^#) } -// ENUM_AVAIL_1: Begin completions, 2 items +// ENUM_AVAIL_1: Begin completions, 3 items // ENUM_AVAIL_1-NOT: AAA // ENUM_AVAIL_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: aaa[#EnumAvail1#]; // ENUM_AVAIL_1-DAG: Decl[EnumElement]/ExprSpecific/NotRecommended/TypeRelation[Identical]: BBB[#EnumAvail1#]; +// ENUM_AVAIL_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): EnumAvail1#})[#(into: inout Hasher) -> Void#]; // ENUM_AVAIL_1-NOT: AAA // ENUM_AVAIL_1: End completions @@ -444,11 +461,11 @@ func testAvail2(_ x: OptionsAvail1) { testAvail2(.#^OPTIONS_AVAIL_1^#) } // OPTIONS_AVAIL_1: Begin completions -// ENUM_AVAIL_1-NOT: AAA +// OPTIONS_AVAIL_1-NOT: AAA // OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: aaa[#OptionsAvail1#]; // OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/ExprSpecific/NotRecommended/TypeRelation[Identical]: BBB[#OptionsAvail1#]; // OPTIONS_AVAIL_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init({#rawValue: Int#})[#OptionsAvail1#] -// ENUM_AVAIL_1-NOT: AAA +// OPTIONS_AVAIL_1-NOT: AAA // OPTIONS_AVAIL_1: End completions func testWithLiteral1() { @@ -460,8 +477,9 @@ func testWithLiteral1() { } let s: S _ = s.takeEnum(thing: .#^WITH_LITERAL_1^#, other: 1.0) -// WITH_LITERAL_1: Begin completions, 1 items +// WITH_LITERAL_1: Begin completions, 2 items // WITH_LITERAL_1-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: myCase[#S.MyEnum#]; +// WITH_LITERAL_1-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): S.MyEnum#})[#(into: inout Hasher) -> Void#]; // WITH_LITERAL_1-NEXT: End completions } func testWithLiteral2() { @@ -484,8 +502,9 @@ func testWithLiteral3() { func takeEnum(thing: MyEnum, other: Double) {} func test(s: S) { _ = s.takeEnum(thing: .#^WITH_LITERAL_3^#, other: 1.0) -// WITH_LITERAL_3: Begin completions, 1 items +// WITH_LITERAL_3: Begin completions, 2 items // WITH_LITERAL_3-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: myCase[#MyEnum#]; +// WITH_LITERAL_3-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MyEnum#})[#(into: inout Hasher) -> Void#]; // WITH_LITERAL_3-NEXT: End completions } } @@ -521,11 +540,13 @@ func testNonOptSet() { let x: NonOptSet x = .#^NON_OPT_SET_1^# } -// NON_OPT_SET_1: Begin completions, 4 items +// NON_OPT_SET_1: Begin completions, 6 items // NON_OPT_SET_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: a[#NonOptSet#] +// NON_OPT_SET_1-DAG: Decl[StaticVar]/CurrNominal: wrongType[#Int#]; // NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init({#x: Int#}, {#y: Int#})[#NonOptSet#] // NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#NonOptSet#] // NON_OPT_SET_1-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: b()[#NonOptSet#] +// NON_OPT_SET_1-DAG: Decl[InstanceMethod]/ExprSpecific/TypeRelation[Identical]: notStatic({#(self): NonOptSet#})[#() -> NonOptSet#]; // NON_OPT_SET_1: End completions func testNonOptSet() { @@ -562,12 +583,12 @@ struct AnotherTy: MyProtocol {} func testSubType() { var _: BaseClass = .#^SUBTYPE_1^# } -// SUBTYPE_1: Begin completions, 3 items -// SUBTYPE_1-NOT: init(failable: +// SUBTYPE_1: Begin completions, 4 items // SUBTYPE_1-NOT: Concrete1( // SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#BaseClass#]; // SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: SubClass()[#BaseClass.SubClass#]; // SUBTYPE_1-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: subInstance[#BaseClass.SubClass#]; +// SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal: init({#failable: Void#})[#BaseClass?#]; // SUBTYPE_1: End completions func testMemberTypealias() { @@ -618,11 +639,11 @@ struct HasCreator { func testHasStaticClosure() { let _: HasCreator = .#^STATIC_CLOSURE_1^# } -// STATIC_CLOSURE_1: Begin completions, 2 items +// STATIC_CLOSURE_1: Begin completions, 3 items // STATIC_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#HasCreator#]; // FIXME: Suggest 'create()[#HasCreateor#]', not 'create'. // STATIC_CLOSURE_1-DAG: Decl[StaticVar]/CurrNominal: create[#() -> HasCreator#]; -// STATIC_CLOSURE_1-NOT: create_curried +// STATIC_CLOSURE_1-DAG: Decl[StaticVar]/CurrNominal: create_curried[#() -> () -> HasCreator#]; // STATIC_CLOSURE_1: End completions struct HasOverloaded { @@ -633,11 +654,13 @@ struct HasOverloaded { } func testOverload(val: HasOverloaded) { let _ = val.takeEnum(.#^OVERLOADED_METHOD_1^#) -// OVERLOADED_METHOD_1: Begin completions, 4 items +// OVERLOADED_METHOD_1: Begin completions, 6 items // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; name=South // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; name=North +// OVERLOADED_METHOD_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: East[#SomeEnum2#]; name=East // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: West[#SomeEnum2#]; name=West +// OVERLOADED_METHOD_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum2#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_METHOD_1: End completions let _ = HasOverloaded.init(e: .#^OVERLOADED_INIT_1^#) @@ -761,10 +784,10 @@ extension MyStruct where T: OtherProtocol { func receiveMyStructOfMyProtocol(value: MyStruct) {} func testTypeParamInContextType() { receiveMyStructOfMyProtocol(value: .#^TYPEPARAM_IN_CONTEXTTYPE_1^#) -// TYPEPARAM_IN_CONTEXTTYPE_1: Begin completions, 2 items -// TYPEPARAM_IN_CONTEXTTYPE_1-NOT: otherProtocolOption +// TYPEPARAM_IN_CONTEXTTYPE_1: Begin completions, 3 items // TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[Constructor]/CurrNominal: init()[#MyStruct#]; // TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: myProtocolOption[#MyStruct#]; +// TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[StaticVar]/CurrNominal: otherProtocolOption[#MyStruct#]; // TYPEPARAM_IN_CONTEXTTYPE_1: End completions } @@ -795,11 +818,13 @@ func testClosureReturnTypeForOverloaded() { overloadedClosureRcv { .#^OVERLOADED_CLOSURE_RETURN^# } -// OVERLOADED_CLOSURE_RETURN: Begin completions, 4 items +// OVERLOADED_CLOSURE_RETURN: Begin completions, 6 items // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; +// OVERLOADED_CLOSURE_RETURN-DAG: Decl[InstanceMethod]/CurrNominal: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: East[#SomeEnum2#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: West[#SomeEnum2#]; +// OVERLOADED_CLOSURE_RETURN-DAG: Decl[InstanceMethod]/CurrNominal: hash({#(self): SomeEnum2#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_CLOSURE_RETURN: End completions } From 352adc3b5de1b7cb92319564ce9a52e26f2571a1 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 24 Aug 2020 18:10:27 -0400 Subject: [PATCH 376/663] Remove Argument from UnresolvedMemberExpr Instead, an expresison like `.foo()` is represented as an `UnresolvedMemberExpr` nested inside a `CallExpr`. --- include/swift/AST/Expr.h | 79 ++-------- include/swift/AST/Pattern.h | 3 + lib/AST/ASTDumper.cpp | 7 +- lib/AST/ASTWalker.cpp | 12 +- lib/AST/Expr.cpp | 55 ------- lib/IDE/ExprContextAnalysis.cpp | 146 ++++-------------- lib/IDE/ExprContextAnalysis.h | 4 - lib/IDE/SwiftSourceDocInfo.cpp | 4 - lib/Parse/ParseExpr.cpp | 56 +------ lib/Sema/CSApply.cpp | 33 +--- lib/Sema/CSDiagnostics.cpp | 16 +- lib/Sema/CSGen.cpp | 36 +---- lib/Sema/CSSimplify.cpp | 35 +++-- lib/Sema/ConstraintSystem.cpp | 36 +---- lib/Sema/TypeCheckConstraints.cpp | 7 - lib/Sema/TypeCheckPattern.cpp | 20 ++- test/IDE/complete_call_arg.swift | 44 +++++- test/expr/delayed-ident/member_chains.swift | 49 +++++- test/stmt/statements.swift | 2 +- tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp | 3 - 20 files changed, 190 insertions(+), 457 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index d292a00d17fbf..872e3da08a35f 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -249,17 +249,8 @@ class alignas(8) Expr { NumArgLabels : 16 ); - SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 1+1+1+16, - /// Whether the UnresolvedMemberExpr has arguments. - HasArguments : 1, - /// Whether the UnresolvedMemberExpr also has source locations for the - /// argument label. - HasArgLabelLocs : 1, - /// Whether the last argument is a trailing closure. - HasTrailingClosure : 1, - : NumPadBits, - /// # of argument labels stored after the UnresolvedMemberExpr. - NumArgLabels : 16 + SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 2, + FunctionRefKind : 2 ); SWIFT_INLINE_BITFIELD(OverloadSetRefExpr, Expr, 2, @@ -1841,71 +1832,35 @@ class DynamicSubscriptExpr final /// member, which is to be resolved with context sensitive type information into /// bar.foo. These always have unresolved type. class UnresolvedMemberExpr final - : public Expr, - public TrailingCallArguments { + : public Expr { SourceLoc DotLoc; DeclNameLoc NameLoc; DeclNameRef Name; - Expr *Argument; - - UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, - DeclNameRef name, Expr *argument, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit); public: - /// Create a new unresolved member expression with no arguments. - static UnresolvedMemberExpr *create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - bool implicit); - - /// Create a new unresolved member expression. - static UnresolvedMemberExpr *create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit); + UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, DeclNameRef name, + bool implicit) + : Expr(ExprKind::UnresolvedMember, implicit), DotLoc(dotLoc), + NameLoc(nameLoc), Name(name) {} DeclNameRef getName() const { return Name; } DeclNameLoc getNameLoc() const { return NameLoc; } SourceLoc getDotLoc() const { return DotLoc; } - Expr *getArgument() const { return Argument; } - void setArgument(Expr *argument) { Argument = argument; } - /// Whether this reference has arguments. - bool hasArguments() const { - return Bits.UnresolvedMemberExpr.HasArguments; - } - - unsigned getNumArguments() const { - return Bits.UnresolvedMemberExpr.NumArgLabels; - } - - bool hasArgumentLabelLocs() const { - return Bits.UnresolvedMemberExpr.HasArgLabelLocs; - } + SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } - /// Whether this call with written with a trailing closure. - bool hasTrailingClosure() const { - return Bits.UnresolvedMemberExpr.HasTrailingClosure; - } + SourceLoc getStartLoc() const { return DotLoc; } + SourceLoc getEndLoc() const { return NameLoc.getSourceRange().End; } - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const { - return getArgument()->getUnlabeledTrailingClosureIndexOfPackedArgument(); + /// Retrieve the kind of function reference. + FunctionRefKind getFunctionRefKind() const { + return static_cast( + Bits.UnresolvedMemberExpr.FunctionRefKind); } - SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } - - SourceLoc getStartLoc() const { return DotLoc; } - SourceLoc getEndLoc() const { - return (Argument ? Argument->getEndLoc() : NameLoc.getSourceRange().End); + /// Set the kind of function reference. + void setFunctionRefKind(FunctionRefKind refKind) { + Bits.UnresolvedMemberExpr.FunctionRefKind = static_cast(refKind); } static bool classof(const Expr *E) { diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h index 6424dd12a72f2..13630507bb3a5 100644 --- a/include/swift/AST/Pattern.h +++ b/include/swift/AST/Pattern.h @@ -554,6 +554,9 @@ class EnumElementPattern : public Pattern { bool hasUnresolvedOriginalExpr() const { return ElementDeclOrUnresolvedOriginalExpr.is(); } + void setUnresolvedOriginalExpr(Expr *e) { + ElementDeclOrUnresolvedOriginalExpr = e; + } DeclNameLoc getNameLoc() const { return NameLoc; } SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index fa9efd6ba4c2f..821916d202497 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2108,11 +2108,8 @@ class PrintExpr : public ExprVisitor { void visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { printCommon(E, "unresolved_member_expr") << " name='" << E->getName() << "'"; - printArgumentLabels(E->getArgumentLabels()); - if (E->getArgument()) { - OS << '\n'; - printRec(E->getArgument()); - } + PrintWithColorRAII(OS, ExprModifierColor) + << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDotSelfExpr(DotSelfExpr *E) { diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index c6884f049b44e..ef2ba5afb7cbf 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -504,17 +504,7 @@ class Traversal : public ASTVisitorgetArgument()) { - if (auto arg = doIt(E->getArgument())) { - E->setArgument(arg); - return E; - } - - return nullptr; - } - return E; - } + Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { return E; } Expr *visitOpaqueValueExpr(OpaqueValueExpr *E) { return E; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 113b8e499a136..fe8023090e6f8 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1608,61 +1608,6 @@ DynamicSubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index, hasTrailingClosure, decl, implicit); } -UnresolvedMemberExpr::UnresolvedMemberExpr(SourceLoc dotLoc, - DeclNameLoc nameLoc, - DeclNameRef name, Expr *argument, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit) - : Expr(ExprKind::UnresolvedMember, implicit), - DotLoc(dotLoc), NameLoc(nameLoc), Name(name), Argument(argument) { - Bits.UnresolvedMemberExpr.HasArguments = (argument != nullptr); - Bits.UnresolvedMemberExpr.NumArgLabels = argLabels.size(); - Bits.UnresolvedMemberExpr.HasArgLabelLocs = !argLabelLocs.empty(); - Bits.UnresolvedMemberExpr.HasTrailingClosure = hasTrailingClosure; - initializeCallArguments(argLabels, argLabelLocs); -} - -UnresolvedMemberExpr *UnresolvedMemberExpr::create(ASTContext &ctx, - SourceLoc dotLoc, - DeclNameLoc nameLoc, - DeclNameRef name, - bool implicit) { - size_t size = totalSizeToAlloc({ }, { }); - - void *memory = ctx.Allocate(size, alignof(UnresolvedMemberExpr)); - return new (memory) UnresolvedMemberExpr(dotLoc, nameLoc, name, nullptr, - { }, { }, - /*hasTrailingClosure=*/false, - implicit); -} - -UnresolvedMemberExpr * -UnresolvedMemberExpr::create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit) { - SmallVector argLabelsScratch; - SmallVector argLabelLocsScratch; - Expr *arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, trailingClosures, implicit, - argLabelsScratch, argLabelLocsScratch); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(UnresolvedMemberExpr)); - return new (memory) UnresolvedMemberExpr(dotLoc, nameLoc, name, arg, - argLabels, argLabelLocs, - trailingClosures.size() == 1, - implicit); -} - ArrayRef ApplyExpr::getArgumentLabels( SmallVectorImpl &scratch) const { // Unary operators and 'self' applications have a single, unlabeled argument. diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 787606e321891..23fa5971f7b3c 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -558,6 +558,31 @@ static void collectPossibleCalleesByQualifiedLookup( } } +/// For the given \p unresolvedMemberExpr, collect possible callee types and +/// declarations. +static bool collectPossibleCalleesForUnresolvedMember( + DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr, + SmallVectorImpl &candidates) { + auto collectMembers = [&](Type expectedTy) { + if (!expectedTy->mayHaveMembers()) + return; + collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), + unresolvedMemberExpr->getName(), + candidates); + }; + + // Get the context of the expression itself. + ExprContextInfo contextInfo(&DC, unresolvedMemberExpr); + for (auto expectedTy : contextInfo.getPossibleTypes()) { + collectMembers(expectedTy); + // If this is an optional type, let's also check its base type. + if (auto baseTy = expectedTy->getOptionalObjectType()) { + collectMembers(baseTy->lookThroughAllOptionalTypes()); + } + } + return !candidates.empty(); +} + /// For the given \c callExpr, collect possible callee types and declarations. static bool collectPossibleCalleesForApply( DeclContext &DC, ApplyExpr *callExpr, @@ -599,6 +624,8 @@ static bool collectPossibleCalleesForApply( } else if (auto CRCE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup( DC, CRCE->getArg(), DeclNameRef::createConstructor(), candidates); + } else if (auto *UME = dyn_cast(fnExpr)) { + collectPossibleCalleesForUnresolvedMember(DC, UME, candidates); } if (!candidates.empty()) @@ -662,39 +689,6 @@ static bool collectPossibleCalleesForSubscript( return !candidates.empty(); } -/// For the given \p unresolvedMemberExpr, collect possible callee types and -/// declarations. -static bool collectPossibleCalleesForUnresolvedMember( - DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr, - SmallVectorImpl &candidates) { - auto currModule = DC.getParentModule(); - - auto collectMembers = [&](Type expectedTy) { - if (!expectedTy->mayHaveMembers()) - return; - SmallVector members; - collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), - unresolvedMemberExpr->getName(), - members); - for (auto member : members) { - if (isReferenceableByImplicitMemberExpr(currModule, &DC, expectedTy, - member.Decl)) - candidates.push_back(member); - } - }; - - // Get the context of the expression itself. - ExprContextInfo contextInfo(&DC, unresolvedMemberExpr); - for (auto expectedTy : contextInfo.getPossibleTypes()) { - collectMembers(expectedTy); - // If this is an optional type, let's also check its base type. - if (auto baseTy = expectedTy->getOptionalObjectType()) { - collectMembers(baseTy->lookThroughAllOptionalTypes()); - } - } - return !candidates.empty(); -} - /// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr /// or \c ParenExpr. /// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. @@ -761,11 +755,6 @@ class ExprContextAnalyzer { if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates)) return false; Arg = subscriptExpr->getIndex(); - } else if (auto *unresolvedMemberExpr = dyn_cast(E)) { - if (!collectPossibleCalleesForUnresolvedMember(*DC, unresolvedMemberExpr, - Candidates)) - return false; - Arg = unresolvedMemberExpr->getArgument(); } else { llvm_unreachable("unexpected expression kind"); } @@ -840,7 +829,6 @@ class ExprContextAnalyzer { switch (Parent->getKind()) { case ExprKind::Call: case ExprKind::Subscript: - case ExprKind::UnresolvedMember: case ExprKind::Binary: case ExprKind::PrefixUnary: { analyzeApplyExpr(Parent); @@ -848,8 +836,10 @@ class ExprContextAnalyzer { } case ExprKind::Array: { if (auto type = ParsedExpr->getType()) { - recordPossibleType(type); - break; + if (!type->is()) { + recordPossibleType(type); + break; + } } // Check context types of the array literal expression. @@ -1144,7 +1134,6 @@ class ExprContextAnalyzer { case ExprKind::Assign: case ExprKind::Dictionary: case ExprKind::If: - case ExprKind::UnresolvedMember: return true; case ExprKind::Array: return (!Parent.getAsExpr() || @@ -1153,8 +1142,7 @@ class ExprContextAnalyzer { auto ParentE = Parent.getAsExpr(); return !ParentE || (!isa(ParentE) && !isa(ParentE) && - !isa(ParentE) && - !isa(ParentE)); + !isa(ParentE)); } case ExprKind::Closure: return isSingleExpressionBodyForCodeCompletion( @@ -1228,73 +1216,3 @@ ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) { singleExpressionBody); Analyzer.Analyze(); } - -//===----------------------------------------------------------------------===// -// isReferenceableByImplicitMemberExpr(ModuleD, DeclContext, Type, ValueDecl) -//===----------------------------------------------------------------------===// - -bool swift::ide::isReferenceableByImplicitMemberExpr( - ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD) { - - if (VD->isOperator()) - return false; - - if (T->getOptionalObjectType() && - VD->getModuleContext()->isStdlibModule()) { - // In optional context, ignore '.init()', 'init(nilLiteral:)', - if (isa(VD)) - return false; - // TODO: Ignore '.some()' and '.none' too *in expression - // context*. They are useful in pattern context though. - } - - // Enum element decls can always be referenced by implicit member - // expression. - if (isa(VD)) - return true; - - // Only non-failable constructors are implicitly referenceable. - if (auto CD = dyn_cast(VD)) { - return (!CD->isFailable() || CD->isImplicitlyUnwrappedOptional()); - } - - // Otherwise, check the result type matches the contextual type. - auto declTy = T->getTypeOfMember(CurrModule, VD); - if (declTy->is()) - return false; - - // Member types can also be implicitly referenceable as long as it's - // convertible to the contextual type. - if (auto CD = dyn_cast(VD)) { - declTy = declTy->getMetatypeInstanceType(); - - // Emit construction for the same type via typealias doesn't make sense - // because we are emitting all `.init()`s. - if (declTy->isEqual(T)) - return false; - - // Only non-protocol nominal type can be instantiated. - auto nominal = declTy->getAnyNominal(); - if (!nominal || isa(nominal)) - return false; - - return swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC); - } - - // Only static member can be referenced. - if (!VD->isStatic()) - return false; - - if (isa(VD)) { - // Strip '(Self.Type) ->' and parameters. - declTy = declTy->castTo()->getResult(); - declTy = declTy->castTo()->getResult(); - } else if (auto FT = declTy->getAs()) { - // The compiler accepts 'static var factory: () -> T' for implicit - // member expression. - // FIXME: This emits just 'factory'. We should emit 'factory()' instead. - declTy = FT->getResult(); - } - return declTy->isEqual(T) || - swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC); -} diff --git a/lib/IDE/ExprContextAnalysis.h b/lib/IDE/ExprContextAnalysis.h index 1e0b749ac065c..9c957353b68e0 100644 --- a/lib/IDE/ExprContextAnalysis.h +++ b/lib/IDE/ExprContextAnalysis.h @@ -114,10 +114,6 @@ class ExprContextInfo { } }; -/// Returns whether \p VD is referenceable with implicit member expression. -bool isReferenceableByImplicitMemberExpr( - ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD); - } // namespace ide } // namespace swift diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp index b372b1cba3e39..6f44a3078ac63 100644 --- a/lib/IDE/SwiftSourceDocInfo.cpp +++ b/lib/IDE/SwiftSourceDocInfo.cpp @@ -282,10 +282,6 @@ Stmt *NameMatcher::walkToStmtPost(Stmt *S) { } Expr *NameMatcher::getApplicableArgFor(Expr *E) { - if (auto *UME = dyn_cast(E)) { - if (auto *Arg = UME->getArgument()) - return Arg; - } if (ParentCalls.empty()) return nullptr; auto &Last = ParentCalls.back(); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1d3a63a826d11..1a42b3832b09a 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1612,60 +1612,8 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { return makeParserErrorResult(new (Context) ErrorExpr(DotLoc)); SyntaxContext->createNodeInPlace(SyntaxKind::MemberAccessExpr); - // Check for a () suffix, which indicates a call when constructing - // this member. Note that this cannot be the start of a new line. - if (Tok.isFollowingLParen()) { - SourceLoc lParenLoc, rParenLoc; - SmallVector args; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector trailingClosures; - - ParserStatus status = parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/true, isExprBasic, - lParenLoc, args, argLabels, - argLabelLocs, - rParenLoc, - trailingClosures, - SyntaxKind::TupleExprElementList); - SyntaxContext->createNodeInPlace(SyntaxKind::FunctionCallExpr); - return makeParserResult( - status, - UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - lParenLoc, args, argLabels, - argLabelLocs, rParenLoc, - trailingClosures, - /*implicit=*/false)); - } - - // Check for a trailing closure, if allowed. - if (Tok.is(tok::l_brace) && isValidTrailingClosure(isExprBasic, *this)) { - if (SyntaxContext->isEnabled()) { - // Add dummy blank argument list to the call expression syntax. - SyntaxContext->addSyntax( - ParsedSyntaxRecorder::makeBlankTupleExprElementList( - leadingTriviaLoc(), *SyntaxContext)); - } - - SmallVector trailingClosures; - auto result = parseTrailingClosures(isExprBasic, NameLoc.getSourceRange(), - trailingClosures); - if (trailingClosures.empty()) - return nullptr; - - SyntaxContext->createNodeInPlace(SyntaxKind::FunctionCallExpr); - // Handle .foo by just making an AST node. - return makeParserResult( - result, UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - SourceLoc(), {}, {}, {}, - SourceLoc(), trailingClosures, - /*implicit=*/false)); - } - - // Handle .foo by just making an AST node. - return makeParserResult( - UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - /*implicit=*/false)); + return makeParserResult(new (Context) UnresolvedMemberExpr( + DotLoc, NameLoc, Name, /*implicit=*/false)); } case tok::kw_super: // 'super' diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index bcbb363713730..25c85383a9e55 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -860,12 +860,9 @@ namespace { } // Similarly, ".foo(...)" really applies two argument lists. - if (auto *unresolvedMemberExpr = dyn_cast(prev)) { - if (unresolvedMemberExpr->hasArguments() || - unresolvedMemberExpr->hasTrailingClosure()) - return 2; - return 1; - } + if (isa(prev) && + isa(cast(prev)->getFn())) + return 2; return getArgCount(maxArgCount); }(); @@ -2786,30 +2783,6 @@ namespace { if (!result) return nullptr; - auto getType = [&](Expr *E) -> Type { return cs.getType(E); }; - - // If there was an argument, apply it. - if (auto arg = expr->getArgument()) { - // Get the callee locator. Note this may be different to the locator for - // the member being referenced for things like callAsFunction. - auto *calleeLoc = cs.getCalleeLocator(exprLoc); - - // Build and finish the apply. - ApplyExpr *apply = CallExpr::create( - ctx, result, arg, expr->getArgumentLabels(), - expr->getArgumentLabelLocs(), expr->hasTrailingClosure(), - /*implicit=*/expr->isImplicit(), Type(), getType); - result = finishApply(apply, Type(), exprLoc, calleeLoc); - - // FIXME: Application could fail, because some of the solutions - // are not expressible in AST (yet?), like certain tuple-to-tuple - // conversions. Better solution here would be not to form solutions - // which couldn't be applied by e.g. detecting situations like that - // and inserting fixes early. - if (!result) - return nullptr; - } - // Check for ambiguous member if the base is an Optional if (baseTy->getOptionalObjectType()) { diagnoseAmbiguousNominalMember(baseTy, result); diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 066da31ad5341..acb66a12e83bd 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1443,10 +1443,7 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { } else if (isa(diagExpr)) { subElementDiagID = diag::assignment_subscript_has_immutable_base; } else if (auto *UME = dyn_cast(diagExpr)) { - if (UME->hasArguments()) - subElementDiagID = diag::assignment_lhs_is_apply_expression; - else - subElementDiagID = diag::assignment_lhs_is_immutable_property; + subElementDiagID = diag::assignment_lhs_is_immutable_property; } else { subElementDiagID = diag::assignment_lhs_is_immutable_variable; } @@ -4500,9 +4497,6 @@ MissingArgumentsFailure::getCallInfo(ASTNode anchor) const { return std::make_tuple(call->getFn(), call->getArg(), call->getNumArguments(), call->getUnlabeledTrailingClosureIndex()); - } else if (auto *UME = getAsExpr(anchor)) { - return std::make_tuple(UME, UME->getArgument(), UME->getNumArguments(), - UME->getUnlabeledTrailingClosureIndex()); } else if (auto *SE = getAsExpr(anchor)) { return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(), SE->getUnlabeledTrailingClosureIndex()); @@ -6341,6 +6335,14 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { // Member reference could be wrapped into a number of parens // e.g. `((.foo))`. auto *parentExpr = findParentExpr(anchor); + + // Look through immediate call of unresolved member (e.g., `.foo(0)`). + if (parentExpr && isa(parentExpr)) + parentExpr = findParentExpr(parentExpr); + + // FIXME: We should probably look through the entire member chain so that + // something like `let _ = .foo().bar` gets the "no contextual type" error + // rather than the "Cannot infer contextual base" error. UnresolvedMemberChainResultExpr *resultExpr = nullptr; if (parentExpr && isa(parentExpr)) { resultExpr = cast(parentExpr); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index f03ec3297463a..c83879fb2a3c1 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1441,10 +1441,6 @@ namespace { auto baseLocator = CS.getConstraintLocator( expr, ConstraintLocator::MemberRefBase); - FunctionRefKind functionRefKind = - expr->getArgument() ? FunctionRefKind::DoubleApply - : FunctionRefKind::Compound; - auto memberLocator = CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember); @@ -1466,37 +1462,9 @@ namespace { // member, i.e., an enum case or a static variable. auto baseMetaTy = MetatypeType::get(baseTy); CS.addUnresolvedValueMemberConstraint(baseMetaTy, expr->getName(), - memberTy, CurDC, functionRefKind, + memberTy, CurDC, + expr->getFunctionRefKind(), memberLocator); - - // If there is an argument, apply it. - if (auto arg = expr->getArgument()) { - // Create a new type variable for the result of the function. - auto outputTy = CS.createTypeVariable( - CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), - TVO_CanBindToNoEscape); - - // The function/enum case must be callable with the given argument. - - // FIXME: Redesign the AST so that an UnresolvedMemberExpr directly - // stores a list of arguments together with their inout-ness, instead of - // a single ParenExpr or TupleExpr argument. - SmallVector params; - AnyFunctionType::decomposeInput(CS.getType(arg), params); - - CS.addConstraint(ConstraintKind::ApplicableFunction, - FunctionType::get(params, outputTy), - memberTy, - CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); - - associateArgumentLabels( - CS.getConstraintLocator(expr), - {expr->getArgumentLabels(), - expr->getUnlabeledTrailingClosureIndex()}); - return outputTy; - } - - // Otherwise, the result is just the type of the member. return memberTy; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b252b1773756f..96d6fc2cee266 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6755,22 +6755,27 @@ static ConstraintFix *validateInitializerRef(ConstraintSystem &cs, } else if (auto *CE = getAsExpr(anchor)) { baseExpr = CE->getFn(); baseType = getType(baseExpr); - // If this is an initializer call without explicit mention - // of `.init` on metatype value. - if (auto *AMT = baseType->getAs()) { - auto instanceType = AMT->getInstanceType()->getWithoutParens(); - if (!cs.isTypeReference(baseExpr)) { - if (baseType->is() && - instanceType->isAnyExistentialType()) { - return AllowInvalidInitRef::onProtocolMetatype( - cs, baseType, init, cs.isStaticallyDerivedMetatype(baseExpr), - baseExpr->getSourceRange(), locator); - } + // FIXME: Historically, UnresolvedMemberExprs have allowed implicit + // construction through a metatype value, but this should probably be + // illegal. + if (!isa(baseExpr)) { + // If this is an initializer call without explicit mention + // of `.init` on metatype value. + if (auto *AMT = baseType->getAs()) { + auto instanceType = AMT->getInstanceType()->getWithoutParens(); + if (!cs.isTypeReference(baseExpr)) { + if (baseType->is() && + instanceType->isAnyExistentialType()) { + return AllowInvalidInitRef::onProtocolMetatype( + cs, baseType, init, cs.isStaticallyDerivedMetatype(baseExpr), + baseExpr->getSourceRange(), locator); + } - if (!instanceType->isExistentialType() || - instanceType->isAnyExistentialType()) { - return AllowInvalidInitRef::onNonConstMetatype(cs, baseType, init, - locator); + if (!instanceType->isExistentialType() || + instanceType->isAnyExistentialType()) { + return AllowInvalidInitRef::onNonConstMetatype(cs, baseType, init, + locator); + } } } } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index a933da4a6857c..e186f5d321bfe 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -562,21 +562,7 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator( } if (auto *UME = getAsExpr(anchor)) { - auto *calleeLoc = - getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); - - // Handle special cases for applies of non-function types. - // FIXME: Consider re-designing the AST such that an unresolved member expr - // with arguments uses a CallExpr, which would make this logic unnecessary - // and clean up a bunch of other special cases. Doing so may require a bit - // of hacking in CSGen though. - if (UME->hasArguments()) { - if (auto overload = getOverloadFor(calleeLoc)) { - if (auto *loc = getSpecialFnCalleeLoc(overload->boundType)) - return loc; - } - } - return calleeLoc; + return getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); } if (isExpr(anchor)) @@ -3153,9 +3139,7 @@ static bool diagnoseAmbiguityWithContextualType( auto type = solution.simplifyType(overload.boundType); - if (isExpr(anchor) || isExpr(anchor) || - (isExpr(anchor) && - castToExpr(anchor)->hasArguments())) { + if (isExpr(anchor) || isExpr(anchor)) { auto fnType = type->castTo(); DE.diagnose( loc, diag::cannot_convert_candidate_result_to_contextual_type, @@ -3665,11 +3649,6 @@ void constraints::simplifyLocator(ASTNode &anchor, continue; } - if (auto *UME = getAsExpr(anchor)) { - anchor = UME->getArgument(); - path = path.slice(1); - continue; - } break; } @@ -3694,15 +3673,6 @@ void constraints::simplifyLocator(ASTNode &anchor, continue; } - // The unresolved member itself is the function. - if (auto unresolvedMember = getAsExpr(anchor)) { - if (unresolvedMember->getArgument()) { - anchor = unresolvedMember; - path = path.slice(1); - continue; - } - } - break; case ConstraintLocator::AutoclosureResult: @@ -3898,8 +3868,6 @@ Expr *constraints::getArgumentExpr(ASTNode node, unsigned index) { Expr *argExpr = nullptr; if (auto *AE = dyn_cast(expr)) argExpr = AE->getArg(); - else if (auto *UME = dyn_cast(expr)) - argExpr = UME->getArgument(); else if (auto *SE = dyn_cast(expr)) argExpr = SE->getIndex(); else diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 5c16de3953a8c..f0226a6d094e8 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -1125,13 +1125,6 @@ namespace { } } - // If this is an unresolved member with a call argument (e.g., - // .some(x)), record the argument expression. - if (auto unresolvedMember = dyn_cast(expr)) { - if (auto arg = unresolvedMember->getArgument()) - CallArgs.insert(arg); - } - // FIXME(diagnostics): `InOutType` could appear here as a result // of successful re-typecheck of the one of the sub-expressions e.g. // `let _: Int = { (s: inout S) in s.bar() }`. On the first diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index b02220919667d..1e5c3a571df6f 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -446,18 +446,12 @@ class ResolvePattern : public ASTVisitorgetArgument()) { - subPattern = getSubExprPattern(arg); - } - if (ume->getName().getBaseName().isSpecial()) return nullptr; return new (Context) EnumElementPattern(ume->getDotLoc(), ume->getNameLoc(), ume->getName(), - subPattern, ume); + nullptr, ume); } // Member syntax 'T.Element' forms a pattern if 'T' is an enum and the @@ -547,6 +541,18 @@ class ResolvePattern : public ASTVisitor(ce->getFn())) return nullptr; + if (isa(ce->getFn())) { + auto *P = visit(ce->getFn()); + if (!P) + return nullptr; + + auto *EEP = cast(P); + EEP->setSubPattern(getSubExprPattern(ce->getArg())); + EEP->setUnresolvedOriginalExpr(ce); + + return P; + } + SmallVector components; if (!ExprToIdentTypeRepr(components, Context).visit(ce->getFn())) return nullptr; diff --git a/test/IDE/complete_call_arg.swift b/test/IDE/complete_call_arg.swift index 07e5d183f7b62..bbd17ff20cd9e 100644 --- a/test/IDE/complete_call_arg.swift +++ b/test/IDE/complete_call_arg.swift @@ -78,11 +78,13 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_AFTERPAREN_2 | %FileCheck %s -check-prefix=STATIC_METHOD_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_SECOND | %FileCheck %s -check-prefix=STATIC_METHOD_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_SKIPPED | %FileCheck %s -check-prefix=STATIC_METHOD_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_OVERLOADED | %FileCheck %s -check-prefix=STATIC_METHOD_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_1 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_3 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_SKIPPED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_OVERLOADED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_1 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND @@ -91,6 +93,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_SKIPPED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_OVERLOADED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARCHETYPE_GENERIC_1 | %FileCheck %s -check-prefix=ARCHETYPE_GENERIC_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PARAM_WITH_ERROR_AUTOCLOSURE| %FileCheck %s -check-prefix=PARAM_WITH_ERROR_AUTOCLOSURE @@ -667,6 +670,8 @@ class TestStaticMemberCall { static func create2(_ arg1: Int, arg2: Int = 0, arg3: Int = 1, arg4: Int = 2) -> TestStaticMemberCall { return TestStaticMemberCall() } + static func createOverloaded(arg1: Int) -> TestStaticMemberCall { TestStaticMemberCall() } + static func createOverloaded(arg1: String) -> String { arg1 } } func testStaticMemberCall() { let _ = TestStaticMemberCall.create1(#^STATIC_METHOD_AFTERPAREN_1^#) @@ -695,24 +700,30 @@ func testStaticMemberCall() { // STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: End completions + + let _ = TestStaticMemberCall.createOverloaded(#^STATIC_METHOD_OVERLOADED^#) +// STATIC_METHOD_OVERLOADED: Begin completions, 2 items +// STATIC_METHOD_OVERLOADED-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// STATIC_METHOD_OVERLOADED-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: String#}[')'][#String#]; name=arg1: String +// STATIC_METHOD_OVERLOADED: End completions } func testImplicitMember() { let _: TestStaticMemberCall = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_1^#) // IMPLICIT_MEMBER_AFTERPAREN_1: Begin completions, 1 items -// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int // IMPLICIT_MEMBER_AFTERPAREN_1: End completions let _: TestStaticMemberCall = .create2(#^IMPLICIT_MEMBER_AFTERPAREN_2^#) // IMPLICIT_MEMBER_AFTERPAREN_2: Begin completions -// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#]; -// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#]; +// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#]; +// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#]; // IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[Struct]/OtherModule[Swift]/IsSystem/TypeRelation[Identical]: Int[#Int#]; // IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Literal[Integer]/None/TypeRelation[Identical]: 0[#Int#]; // IMPLICIT_MEMBER_AFTERPAREN_2: End completions let _: TestStaticMemberCall? = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_3^#) // IMPLICIT_MEMBER_AFTERPAREN_3: Begin completions, 1 items -// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int // IMPLICIT_MEMBER_AFTERPAREN_3: End completions let _: TestStaticMemberCall = .create2(1, #^IMPLICIT_MEMBER_SECOND^#) @@ -728,6 +739,12 @@ func testImplicitMember() { // IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: End completions + + let _: TestStaticMemberCall = .createOverloaded(#^IMPLICIT_MEMBER_OVERLOADED^#) +// IMPLICIT_MEMBER_OVERLOADED: Begin completions, 2 items +// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: String#}[')'][#String#]; name=arg1: String +// IMPLICIT_MEMBER_OVERLOADED: End completions } func testImplicitMemberInArrayLiteral() { struct Receiver { @@ -741,8 +758,12 @@ func testImplicitMemberInArrayLiteral() { // Same as IMPLICIT_MEMBER_AFTERPAREN_1. ]) Receiver([ + .create1(x: 1), .create2(#^IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_2^#), // Same as IMPLICIT_MEMBER_AFTERPAREN_2. + ]) + Receiver([ + .create1(x: 1), .create2(1, #^IMPLICIT_MEMBER_ARRAY_1_SECOND^# // Same as IMPLICIT_MEMBER_SECOND. ]) @@ -751,15 +772,22 @@ func testImplicitMemberInArrayLiteral() { // Same as IMPLICIT_MEMBER_SKIPPED. .create1(x: 12) ]) + Receiver(arg1: 12, arg2: [ + .create1(x: 12), + .createOverloaded(#^IMPLICIT_MEMBER_ARRAY_1_OVERLOADED^#) + // Same as IMPLICIT_MEMBER_OVERLOADED. + ]) let _: [TestStaticMemberCall] = [ .create1(#^IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_1^#), - // Same as STATIC_METHOD_AFTERPAREN_1. + // Same as IMPLICIT_MEMBER_AFTERPAREN_1. .create2(#^IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_2^#), - // Same as STATIC_METHOD_AFTERPAREN_2. + // Same as IMPLICIT_MEMBER_AFTERPAREN_2. .create2(1, #^IMPLICIT_MEMBER_ARRAY_2_SECOND^#), - // Same as STATIC_METHOD_SECOND. + // Same as IMPLICIT_MEMBER_SECOND. .create2(1, arg3: 2, #^IMPLICIT_MEMBER_ARRAY_2_SKIPPED^#), - // Same as STATIC_METHOD_SKIPPED. + // Same as IMPLICIT_MEMBER_SKIPPED. + .createOverloaded(#^IMPLICIT_MEMBER_ARRAY_2_OVERLOADED^#), + // Same as IMPLICIT_MEMBER_OVERLOADED ] } diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index ed694ab8ad98c..aee57a5eae1f9 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -54,6 +54,11 @@ struct ImplicitMembers: Equatable { func getAnotherOptional(arg: Int) -> ImplicitMembers? { ImplicitMembers() } + + static func takesClosure(_: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + static func takesArgClosure(_: Int, _: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + func methodTakesClosure(_: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + func methodTakesArgClosure(_: Int, _: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } subscript(arg: Void) -> ImplicitMembers { get { ImplicitMembers() } @@ -165,6 +170,13 @@ let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.another // FIXME: This should be allowed // let _: ImplicitMembers? = .superOptional???.another +let _: ImplicitMembers = .takesClosure { _ in } +let _: ImplicitMembers = .takesArgClosure(0) { _ in } +let _: ImplicitMembers = .implicit.methodTakesClosure { _ in } +let _: ImplicitMembers = .implicit.methodTakesArgClosure(0) { _ in } +let _: ImplicitMembers? = .optional?.methodTakesClosure { _ in } +let _: ImplicitMembers? = .optional?.methodTakesArgClosure(0) { _ in } + let _: ImplicitMembers = .implicit[()] let _: ImplicitMembers = .implicit[optional: ()]! let _: ImplicitMembers? = .implicit[optional: ()] @@ -212,14 +224,14 @@ func testLValues() { .implicitLet = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} .implicitImmutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} - .createImplicit() = local; // expected-error {{cannot assign to value: 'createImplicit' is a method}} + .createImplicit() = local; // expected-error {{expression is not assignable: function call returns immutable value}} .implicit.another = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} .implicit[immutable: ()] = local; // expected-error {{cannot assign through subscript: subscript is get-only}} .implicit.getAnother() = local; // expected-error {{expression is not assignable: function call returns immutable value}} .implicitLet.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} .implicitImmutable.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} - .createImplicit().anotherMutable = local; // expected-error {{cannot assign to value: 'createImplicit' is a method}} + .createImplicit().anotherMutable = local; // expected-error {{cannot assign to property: function call returns immutable value}} .implicit.another.anotherMutable = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} .implicit[immutable: ()].anotherMutable = local; // expected-error {{cannot assign to property: subscript is get-only}} .implicit.getAnother().anotherMutable = local; // expected-error {{cannot assign to property: function call returns immutable value}} @@ -279,3 +291,36 @@ implicit(.implicit.anotherString.anotherStringInt) // expected-error {{member ch implicit(.implicit.getAnotherString().anotherStringInt) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} implicit(.implicit.anotherString.getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} implicit(.implicit.getAnotherString().getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} + +// Implicit member syntax can be used to apply curried instance methods: +struct Curried { + func method() -> Curried { Curried() } + func method(with arg: Int) -> Curried { Curried() } + func method(with arg1: Int, and arg2: String) -> Curried { Curried() } + func takesClosure(_: (Int) -> Void) -> Curried { Curried() } + func takesArgClosure(_: Int, _: (Int) -> Void) -> Curried { Curried() } + static func curried(_ _self: Curried) -> () -> Curried{ return { _self } } + static func curriedWithArgs(_ _self: Curried) -> (Int, String) -> Curried { return { _, _ in _self } } +} + +let _: Curried = .method(Curried())() +let _: Curried = .method(Curried())(with: 0) +let _: Curried = .method(Curried())(with: 0, and: "") +let _: Curried = .takesClosure(Curried())() { _ in } +let _: Curried = .takesArgClosure(Curried())(0) { _ in } +let _: Curried = .curried(Curried())() +let _: Curried = .curriedWithArgs(Curried())(0, "") + + +struct CurriedGeneric { + func create(_: U.Type) -> CurriedGeneric { return CurriedGeneric() } +} + +extension CurriedGeneric where T == Int { + func createInt() -> Self { + return self + } +} + +let _: CurriedGeneric = .createInt(CurriedGeneric())() +let _: CurriedGeneric = .create(CurriedGeneric())(Int.self) diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift index b2594eb8f3398..93de7f6efabc8 100644 --- a/test/stmt/statements.swift +++ b/test/stmt/statements.swift @@ -280,7 +280,7 @@ func RepeatWhileStmt4() { func brokenSwitch(_ x: Int) -> Int { switch x { - case .Blah(var rep): // expected-error{{pattern cannot match values of type 'Int'}} + case .Blah(var rep): // expected-error{{type 'Int' has no member 'Blah'}} return rep } } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp index 6b0fe110a774c..d77474f197d5c 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp @@ -1601,9 +1601,6 @@ class PlaceholderExpansionScanner { if (auto *CE = dyn_cast(E)) { // Call expression can have argument. Arg = CE->getArg(); - } else if (auto UME = dyn_cast(E)) { - // Unresolved member can have argument too. - Arg = UME->getArgument(); } if (!Arg) return false; From 30e52be19cca65a503fa2df6fb5d320fc2e1730d Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Wed, 26 Aug 2020 22:29:50 -0400 Subject: [PATCH 377/663] [AST] Properly initialize FunctionRefKind for UnresolvedMemberExpr --- include/swift/AST/Expr.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 872e3da08a35f..b53a279a93b4c 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -1841,7 +1841,21 @@ class UnresolvedMemberExpr final UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, DeclNameRef name, bool implicit) : Expr(ExprKind::UnresolvedMember, implicit), DotLoc(dotLoc), - NameLoc(nameLoc), Name(name) {} + NameLoc(nameLoc), Name(name) { + // FIXME: Really, we should be setting this to `FunctionRefKind::Compound` + // if `NameLoc` is compound, but this would be a source break for cases like + // ``` + // struct S { + // static func makeS(_: Int) -> S! { S() } + // } + // + // let s: S = .makeS(_:)(0) + // ``` + // Instead, we should store compound-ness as a separate bit from applied/ + // unapplied. + Bits.UnresolvedMemberExpr.FunctionRefKind = + static_cast(FunctionRefKind::Unapplied); + } DeclNameRef getName() const { return Name; } DeclNameLoc getNameLoc() const { return NameLoc; } From d8878d2ab2dc035d7c10097b7f2536b14fd8ef29 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Wed, 26 Aug 2020 22:30:55 -0400 Subject: [PATCH 378/663] [Tests] Add IUO tests for implicit member chains --- test/expr/delayed-ident/member_chains.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index aee57a5eae1f9..2691574dbd321 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -27,6 +27,10 @@ struct ImplicitMembers: Equatable { } static var superOptional: ImplicitMembers??? = ImplicitMembers() + static func createIUOArg(_: Int) -> ImplicitMembers { ImplicitMembers() } + var anotherIUO: ImplicitMembers! { ImplicitMembers() } + func getAnotherIUO() -> ImplicitMembers! { ImplicitMembers() } + var another: ImplicitMembers { ImplicitMembers() } var anotherMutable: ImplicitMembers { get { ImplicitMembers() } @@ -115,6 +119,16 @@ let _: ImplicitMembers = .implicit.another.another.another.another.another let _: ImplicitMembers = .implicit.getAnother().getAnother().getAnother().getAnother().getAnother() let _: ImplicitMembers = .implicit.getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0) +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0).anotherIUO +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0).anotherIUO +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0).anotherIUO + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0).getAnotherIUO() +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0).getAnotherIUO() +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0).getAnotherIUO() + +let _: ImplicitMembers = .createIUOArg(_:)(0) + let _: ImplicitMembers = .optional! let _: ImplicitMembers = .optional!.another let _: ImplicitMembers = .createOptional()!.another @@ -122,6 +136,10 @@ let _: ImplicitMembers = .optional!.anotherOptional! let _: ImplicitMembers = .createOptional()!.anotherOptional! let _: ImplicitMembers = .optional!.getAnotherOptional()! let _: ImplicitMembers = .createOptional()!.getAnotherOptional()! +let _: ImplicitMembers = .implicit.getAnotherIUO() +let _: ImplicitMembers = .createImplicit().anotherIUO +let _: ImplicitMembers = .implicit.anotherIUO +let _: ImplicitMembers = .createImplicit().anotherIUO let _: ImplicitMembers = .optional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{35-35= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{35-35=!}} let _: ImplicitMembers = .implicit.anotherOptional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{51-51= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{51-51=!}} @@ -167,6 +185,8 @@ let _: ImplicitMembers? = .createOptional()?.getAnother() let _: ImplicitMembers? = .createOptional()?.getAnotherOptional() let _: ImplicitMembers? = .createOptional()?.anotherOptional?.another let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.another +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.anotherIUO +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.getAnotherIUO() // FIXME: This should be allowed // let _: ImplicitMembers? = .superOptional???.another From b6c2f89414996e8212d479bde72b09a007b81920 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 25 Aug 2020 23:31:42 -0700 Subject: [PATCH 379/663] [AST] NFC: Fix a typo in the `HasTypeHole` description --- include/swift/AST/Types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index d5fae0c50be9f..e94790e1ea9c0 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -148,7 +148,7 @@ class RecursiveTypeProperties { /// This type contains an OpaqueTypeArchetype. HasOpaqueArchetype = 0x400, - /// This type constains a type hole. + /// This type contains a type hole. HasTypeHole = 0x800, Last_Property = HasTypeHole From 9de7b59388efe456e1b479072ee366917e0e89a0 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Wed, 26 Aug 2020 21:28:30 -0700 Subject: [PATCH 380/663] Subsume SWIFT_STDLIB_USE_NONATOMIC_RC into SWIFT_STDLIB_SINGLE_THREADED_RUNTIME (#33643) --- stdlib/CMakeLists.txt | 10 +--------- stdlib/cmake/modules/AddSwiftStdlib.cmake | 4 ---- stdlib/cmake/modules/SwiftSource.cmake | 2 +- stdlib/public/runtime/MetadataImpl.h | 2 +- test/lit.site.cfg.in | 4 ++-- utils/build-presets.ini | 15 --------------- utils/build-script-impl | 2 -- .../Runtime/weak-reference-racetests.swift | 2 +- validation-test/SILOptimizer/string_switch.swift | 2 +- validation-test/StdlibUnittest/AtomicInt.swift | 2 +- validation-test/StdlibUnittest/RaceTest.swift | 2 +- validation-test/lit.site.cfg.in | 4 ++-- validation-test/stdlib/ArrayBridging.swift | 2 +- validation-test/stdlib/CommandLine.swift | 2 +- validation-test/stdlib/DictionaryBridging.swift | 2 +- validation-test/stdlib/ErrorProtocol.swift | 2 +- 16 files changed, 15 insertions(+), 44 deletions(-) diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index fab91273b97ec..d692ef67d1d70 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -21,18 +21,10 @@ option(SWIFT_RUNTIME_MACHO_NO_DYLD "Build stdlib assuming the runtime environment uses Mach-O but does not support dynamic modules." FALSE) -option(SWIFT_STDLIB_USE_NONATOMIC_RC - "Build the standard libraries and overlays with nonatomic reference count operations enabled" - FALSE) - option(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME - "Build the standard libraries assuming that they will be used in an environment with only a single thread. If set, also forces SWIFT_STDLIB_USE_NONATOMIC_RC to On." + "Build the standard libraries assuming that they will be used in an environment with only a single thread." FALSE) -if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) - set(SWIFT_STDLIB_USE_NONATOMIC_RC TRUE) -endif() - # # End of user-configurable options. # diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 2ce27dc08e0c6..afaf60ac15ede 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -306,10 +306,6 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-DSWIFT_RUNTIME_MACHO_NO_DYLD") endif() - if(SWIFT_STDLIB_USE_NONATOMIC_RC) - list(APPEND result "-DSWIFT_STDLIB_USE_NONATOMIC_RC") - endif() - if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) list(APPEND result "-DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME") endif() diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index 5041c931f06dd..170d891b2d1d5 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -404,7 +404,7 @@ function(_compile_swift_files list(APPEND swift_flags "-enable-library-evolution") endif() - if(SWIFT_STDLIB_USE_NONATOMIC_RC) + if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) list(APPEND swift_flags "-Xfrontend" "-assume-single-threaded") endif() diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h index 1b12fc1000f26..ac455a8cc9938 100644 --- a/stdlib/public/runtime/MetadataImpl.h +++ b/stdlib/public/runtime/MetadataImpl.h @@ -136,7 +136,7 @@ template struct RetainableBoxBase { static constexpr size_t stride = sizeof(T); static constexpr bool isPOD = false; static constexpr bool isBitwiseTakable = true; -#ifdef SWIFT_STDLIB_USE_NONATOMIC_RC +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME static constexpr bool isAtomic = false; #else static constexpr bool isAtomic = true; diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index a6753e644779d..c4511d2110324 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -87,8 +87,8 @@ if "@SWIFT_AST_VERIFIER@" == "TRUE": if "@SWIFT_OPTIMIZED@" == "TRUE": config.available_features.add("optimized_stdlib") -if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE": - config.available_features.add("nonatomic_rc") +if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": + config.available_features.add("single_threaded_runtime") if "@SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS@" == "TRUE": config.available_features.add('runtime_function_counters') diff --git a/utils/build-presets.ini b/utils/build-presets.ini index ad2ab73e7893f..3a0e27830069e 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -212,21 +212,6 @@ skip-test-ios-simulator skip-test-tvos-simulator skip-test-watchos-simulator -[preset: buildbot,tools=RA,stdlib=RD,single-thread] -mixin-preset= - mixin_buildbot_tools_RA_stdlib_RD - -dash-dash - -# Enable non-atomic build of the stdlib -swift-stdlib-use-nonatomic-rc=true - -# Don't run host tests for iOS, tvOS and watchOS platforms to make the build -# faster. -skip-test-ios-host -skip-test-tvos-host -skip-test-watchos-host - [preset: buildbot,tools=R,stdlib=RD] mixin-preset= mixin_buildbot_tools_R_stdlib_RD diff --git a/utils/build-script-impl b/utils/build-script-impl index 09c1893bc6f9a..078bca624b642 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -186,7 +186,6 @@ KNOWN_SETTINGS=( swift-primary-variant-sdk "" "default SDK for target binaries" swift-runtime-enable-leak-checker "0" "Enable leaks checking routines in the runtime" swift-stdlib-enable-assertions "1" "enable assertions in Swift" - swift-stdlib-use-nonatomic-rc "0" "build the Swift stdlib and overlays with nonatomic reference count operations enabled" swift-tools-enable-lto "" "enable LTO compilation of Swift tools. *NOTE* This does not include the swift standard library and runtime. Must be set to one of 'thin' or 'full'" extra-swift-args "" "Extra arguments to pass to swift modules which match regex. Assumed to be a flattened cmake list consisting of [module_regexp, args, module_regexp, args, ...]" report-statistics "0" "set to 1 to generate compilation statistics files for swift libraries" @@ -1755,7 +1754,6 @@ for host in "${ALL_HOSTS[@]}"; do -DSWIFT_ANALYZE_CODE_COVERAGE:STRING=$(toupper "${SWIFT_ANALYZE_CODE_COVERAGE}") -DSWIFT_STDLIB_BUILD_TYPE:STRING="${SWIFT_STDLIB_BUILD_TYPE}" -DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}") - -DSWIFT_STDLIB_USE_NONATOMIC_RC:BOOL=$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}") -DSWIFT_ENABLE_COMPATIBILITY_OVERRIDES:BOOL=$(true_false "${SWIFT_ENABLE_COMPATIBILITY_OVERRIDES}") -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME:BOOL=$(true_false "${SWIFT_STDLIB_SINGLE_THREADED_RUNTIME}") -DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS:BOOL=$(true_false "${SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS}") diff --git a/validation-test/Runtime/weak-reference-racetests.swift b/validation-test/Runtime/weak-reference-racetests.swift index 1d759c12c60ff..23fc108b6f9f0 100644 --- a/validation-test/Runtime/weak-reference-racetests.swift +++ b/validation-test/Runtime/weak-reference-racetests.swift @@ -1,7 +1,7 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest diff --git a/validation-test/SILOptimizer/string_switch.swift b/validation-test/SILOptimizer/string_switch.swift index b30c80b7cc48e..555c1d972847c 100644 --- a/validation-test/SILOptimizer/string_switch.swift +++ b/validation-test/SILOptimizer/string_switch.swift @@ -4,7 +4,7 @@ // REQUIRES: swift_stdlib_no_asserts,optimized_stdlib // REQUIRES: stress_test // REQUIRES: executable_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest diff --git a/validation-test/StdlibUnittest/AtomicInt.swift b/validation-test/StdlibUnittest/AtomicInt.swift index 00bf5d1c0f8c2..9bc3e8b3f1f8a 100644 --- a/validation-test/StdlibUnittest/AtomicInt.swift +++ b/validation-test/StdlibUnittest/AtomicInt.swift @@ -4,7 +4,7 @@ // RUN: %target-run %t.out // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest diff --git a/validation-test/StdlibUnittest/RaceTest.swift b/validation-test/StdlibUnittest/RaceTest.swift index b3c296036f371..d0f1efc0ef750 100644 --- a/validation-test/StdlibUnittest/RaceTest.swift +++ b/validation-test/StdlibUnittest/RaceTest.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %s -o %t.out // RUN: %target-run %t.out | %FileCheck %s // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest diff --git a/validation-test/lit.site.cfg.in b/validation-test/lit.site.cfg.in index 12aaec7150e00..649281bef0df2 100644 --- a/validation-test/lit.site.cfg.in +++ b/validation-test/lit.site.cfg.in @@ -87,8 +87,8 @@ if "@SWIFT_OPTIMIZED@" == "TRUE": if "@SWIFT_ENABLE_SOURCEKIT_TESTS@" == "TRUE": config.available_features.add('sourcekit') -if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE": - config.available_features.add("nonatomic_rc") +if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": + config.available_features.add("single_threaded_runtime") if "@SWIFT_BUILT_STANDALONE@" == "TRUE": config.available_features.add('standalone_build') diff --git a/validation-test/stdlib/ArrayBridging.swift b/validation-test/stdlib/ArrayBridging.swift index 3fd92fa951dda..6c24bfe8dd0cf 100644 --- a/validation-test/stdlib/ArrayBridging.swift +++ b/validation-test/stdlib/ArrayBridging.swift @@ -9,7 +9,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest import Foundation diff --git a/validation-test/stdlib/CommandLine.swift b/validation-test/stdlib/CommandLine.swift index 610ec08eee400..a43defe135d37 100644 --- a/validation-test/stdlib/CommandLine.swift +++ b/validation-test/stdlib/CommandLine.swift @@ -8,7 +8,7 @@ // RUN: %target-run %t/CommandLineStressTest foo bar baz qux quux corge grault garply waldo fred plugh xyzzy and thud // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime // This file is an empty stub to call into the command line stress test which // houses `main`. diff --git a/validation-test/stdlib/DictionaryBridging.swift b/validation-test/stdlib/DictionaryBridging.swift index 4a2d203e2ca79..eed83d32a67ec 100644 --- a/validation-test/stdlib/DictionaryBridging.swift +++ b/validation-test/stdlib/DictionaryBridging.swift @@ -8,7 +8,7 @@ // REQUIRES: stress_test // REQUIRES: objc_interop -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest import Foundation diff --git a/validation-test/stdlib/ErrorProtocol.swift b/validation-test/stdlib/ErrorProtocol.swift index 5e8a8b7862d38..6b2cf70ef7838 100644 --- a/validation-test/stdlib/ErrorProtocol.swift +++ b/validation-test/stdlib/ErrorProtocol.swift @@ -2,7 +2,7 @@ // REQUIRES: executable_test // REQUIRES: stress_test // REQUIRES: objc_interop -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest From 8f2e53c72d352543226a60d4faab6654bd8e238d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 27 Aug 2020 00:12:51 -0700 Subject: [PATCH 381/663] [AST] Make sure that hole types are always allocated in `ConstraintSolver` arena Since `HoleType` directly as well as other types which could contain holes are bound to a lifetime of constraint system that created them, we need to make sure that such types are always allocated using `ConstraintSolver` arena instead of a permanent one. --- lib/AST/ASTContext.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 6c7e155e8b6d4..8a744f7d03d94 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1466,8 +1466,9 @@ bool ASTContext::hadError() const { /// Retrieve the arena from which we should allocate storage for a type. static AllocationArena getArena(RecursiveTypeProperties properties) { bool hasTypeVariable = properties.hasTypeVariable(); - return hasTypeVariable? AllocationArena::ConstraintSolver - : AllocationArena::Permanent; + bool hasHole = properties.hasTypeHole(); + return hasTypeVariable || hasHole ? AllocationArena::ConstraintSolver + : AllocationArena::Permanent; } void ASTContext::addSearchPath(StringRef searchPath, bool isFramework, @@ -2360,9 +2361,13 @@ Type ErrorType::get(Type originalType) { Type HoleType::get(ASTContext &ctx, OriginatorType originator) { assert(originator); - RecursiveTypeProperties properties = RecursiveTypeProperties::HasTypeHole; + auto properties = reinterpret_cast(originator.getOpaqueValue()) + ->getRecursiveProperties(); + properties |= RecursiveTypeProperties::HasTypeHole; + auto arena = getArena(properties); - return new (ctx, arena) HoleType(ctx, originator, properties); + return new (ctx, arena) + HoleType(ctx, originator, RecursiveTypeProperties::HasTypeHole); } BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth, From 8905f9735c4a7da3d25a44b4f229601ecda00403 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Thu, 27 Aug 2020 11:00:22 -0400 Subject: [PATCH 382/663] [Tests] Update completions for unresolved enum members --- test/IDE/complete_enum_elements.swift | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/test/IDE/complete_enum_elements.swift b/test/IDE/complete_enum_elements.swift index 533fd73ce6515..48d8b01d8b23a 100644 --- a/test/IDE/complete_enum_elements.swift +++ b/test/IDE/complete_enum_elements.swift @@ -138,7 +138,7 @@ enum FooEnum: CaseIterable { // FOO_ENUM_DOT_INVALID-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}} // FOO_ENUM_DOT_INVALID-NEXT: End completions -// FOO_ENUM_DOT_ELEMENTS: Begin completions, 11 items +// FOO_ENUM_DOT_ELEMENTS: Begin completions, 13 items // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo1[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo2[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: alias1[#FooEnum#]; name=alias1 @@ -149,6 +149,8 @@ enum FooEnum: CaseIterable { // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#repeating: FooEnum#}, {#count: Int#})[#Array#]; name=AllCases(repeating: FooEnum, count: Int) // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#unsafeUninitializedCapacity: Int#}, {#initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void##(inout UnsafeMutableBufferPointer, inout Int) throws -> Void#})[' rethrows'][#Array#]; name=AllCases(unsafeUninitializedCapacity: Int, initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void) rethrows // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#from: Decoder#})[' throws'][#Array#]; name=AllCases(from: Decoder) throws +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#repeating: FooEnum#}, {#count: Int#})[#FooEnum.AllCases#]; name=AllCases(repeating: FooEnum, count: Int) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#(elements): Sequence#})[#FooEnum.AllCases#]; name=AllCases(elements: Sequence) // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]; name=allCases // FOO_ENUM_DOT_ELEMENTS-NEXT: End completions @@ -462,17 +464,10 @@ func testWithInvalid1() { func testUnqualified1(x: QuxEnum) { _ = x == .Qux1 || x == .#^UNRESOLVED_2^#Qux2 - // UNRESOLVED_2: Begin completions, 12 items + // UNRESOLVED_2: Begin completions // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux1[#QuxEnum#]; name=Qux1 // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux2[#QuxEnum#]; name=Qux2 // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: UInt#})[#Int#]; name=RawValue(bitPattern: UInt) - // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#(source): Float#})[#Int#]; name=RawValue(source: Float) - // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#(source): Double#})[#Int#]; name=RawValue(source: Double) - // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#(source): Float80#})[#Int#]; name=RawValue(source: Float80) - // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#from: Decoder#})[' throws'][#Int#]; name=RawValue(from: Decoder) throws - // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: OpaquePointer?#})[#Int#]; name=RawValue(bitPattern: OpaquePointer?) - // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: ObjectIdentifier#})[#Int#]; name=RawValue(bitPattern: ObjectIdentifier) - // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: _Pointer?#})[#Int#]; name=RawValue(bitPattern: _Pointer?) // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal: init({#rawValue: Int#})[#QuxEnum?#]; name=init(rawValue: Int) // UNRESOLVED_2-DAG: Decl[InstanceMethod]/Super/IsSystem/TypeRelation[Invalid]: hash({#(self): QuxEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: QuxEnum) // UNRESOLVED_2: End completions From 4cd1b715bdfddc422ce7340cb56492ae7045b4e9 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Wed, 26 Aug 2020 14:31:00 -0400 Subject: [PATCH 383/663] [Runtime] Shrink ConcurrentReadableHashMap a bit. We're using a lot of space on the free lists. Each vector is three words, and we have two of them. Switch to a single linked list. We only need one list, as both kinds of pointers just get free()'d. A linked list optimizes for the common case where the list is empty. This takes us from six words to one. Also make ReaderCount, ElementCount, and ElementCapacity uint32_ts. The size_ts were unnecessarily large and this saves some space on 64-bit systems. While we're in there, add 0/NULL initialization to all elements. The current use in the runtime is unaffected (it's statically allocated) but the local variables used in the test were tripping over this. --- include/swift/Runtime/Concurrent.h | 64 +++++++++++---------- test/stdlib/symbol-visibility-linux.test-sh | 2 + 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 10269653284df..459459c1553b7 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -635,30 +635,49 @@ template struct ConcurrentReadableHashMap { std::atomic &at(size_t i) { return (&Mask)[i]; } }; + /// A simple linked list representing pointers that need to be freed. + struct FreeListNode { + FreeListNode *Next; + void *Ptr; + + static void add(FreeListNode **head, void *ptr) { + auto *newNode = new FreeListNode{*head, ptr}; + *head = newNode; + } + + static void freeAll(FreeListNode **head) { + auto *node = *head; + while (node) { + auto *next = node->Next; + free(node->Ptr); + delete node; + node = next; + } + *head = nullptr; + } + }; + /// The number of readers currently active, equal to the number of snapshot /// objects currently alive. - std::atomic ReaderCount; + std::atomic ReaderCount{0}; /// The number of elements in the elements array. - std::atomic ElementCount; + std::atomic ElementCount{0}; /// The array of elements. - std::atomic Elements; + std::atomic Elements{nullptr}; /// The array of indices. - std::atomic Indices; + std::atomic Indices{nullptr}; /// The writer lock, which must be taken before any mutation of the table. Mutex WriterLock; /// The maximum number of elements that the current elements array can hold. - size_t ElementCapacity; + uint32_t ElementCapacity{0}; - /// The list of element arrays to be freed once no readers are active. - std::vector ElementFreeList; - - /// The list of index arrays to be freed once no readers are active. - std::vector IndicesFreeList; + /// The list of pointers to be freed once no readers are active. + FreeListNode *FreeList{nullptr}; void incrementReaders() { ReaderCount.fetch_add(1, std::memory_order_acquire); @@ -668,24 +687,11 @@ template struct ConcurrentReadableHashMap { ReaderCount.fetch_sub(1, std::memory_order_release); } - /// Free all the arrays in the free lists. - void deallocateFreeList() { - for (auto *storage : ElementFreeList) - free(storage); - ElementFreeList.clear(); - ElementFreeList.shrink_to_fit(); - - for (auto *indices : IndicesFreeList) - free(indices); - IndicesFreeList.clear(); - IndicesFreeList.shrink_to_fit(); - } - /// Free all the arrays in the free lists if there are no active readers. If /// there are active readers, do nothing. void deallocateFreeListIfSafe() { if (ReaderCount.load(std::memory_order_acquire) == 0) - deallocateFreeList(); + FreeListNode::freeAll(&FreeList); } /// Grow the elements array, adding the old array to the free list and @@ -702,7 +708,7 @@ template struct ConcurrentReadableHashMap { ElemTy *newElements = static_cast(malloc(newSize)); if (elements) { memcpy(newElements, elements, elementCount * sizeof(ElemTy)); - ElementFreeList.push_back(elements); + FreeListNode::add(&FreeList, elements); } ElementCapacity = newCapacity; @@ -739,7 +745,7 @@ template struct ConcurrentReadableHashMap { Indices.store(newIndices, std::memory_order_release); - IndicesFreeList.push_back(indices); + FreeListNode::add(&FreeList, indices); return newIndices; } @@ -792,7 +798,7 @@ template struct ConcurrentReadableHashMap { ~ConcurrentReadableHashMap() { assert(ReaderCount.load(std::memory_order_acquire) == 0 && "deallocating ConcurrentReadableHashMap with outstanding snapshots"); - deallocateFreeList(); + FreeListNode::freeAll(&FreeList); } /// Readers take a snapshot of the hash map, then work with the snapshot. @@ -943,8 +949,8 @@ template struct ConcurrentReadableHashMap { Elements.store(nullptr, std::memory_order_relaxed); ElementCapacity = 0; - IndicesFreeList.push_back(indices); - ElementFreeList.push_back(elements); + FreeListNode::add(&FreeList, indices); + FreeListNode::add(&FreeList, elements); deallocateFreeListIfSafe(); } diff --git a/test/stdlib/symbol-visibility-linux.test-sh b/test/stdlib/symbol-visibility-linux.test-sh index 86a7a6dab377d..2472610c3e51b 100644 --- a/test/stdlib/symbol-visibility-linux.test-sh +++ b/test/stdlib/symbol-visibility-linux.test-sh @@ -31,6 +31,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftCore-all.txt @@ -55,6 +56,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftRemoteMirror-all.txt From 1fec2b558414d5042371fcd1c2180798cbd9f4c0 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Thu, 27 Aug 2020 10:25:32 -0700 Subject: [PATCH 384/663] Respect SWIFT_STDLIB_SINGLE_THREADED_RUNTIME and use nonatomic refcounting in swift_retain, swift_release, etc. (#33644) --- stdlib/public/runtime/HeapObject.cpp | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index c409c23731e16..fc644c7a110c4 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -336,7 +336,11 @@ static HeapObject *_swift_retain_(HeapObject *object) { } HeapObject *swift::swift_retain(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_retain(object); +#else CALL_IMPL(swift_retain, (object)); +#endif } SWIFT_RUNTIME_EXPORT @@ -358,7 +362,11 @@ static HeapObject *_swift_retain_n_(HeapObject *object, uint32_t n) { } HeapObject *swift::swift_retain_n(HeapObject *object, uint32_t n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_retain_n(object, n); +#else CALL_IMPL(swift_retain_n, (object, n)); +#endif } SWIFT_RUNTIME_EXPORT @@ -379,7 +387,11 @@ static void _swift_release_(HeapObject *object) { } void swift::swift_release(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_release(object); +#else CALL_IMPL(swift_release, (object)); +#endif } SWIFT_RUNTIME_EXPORT @@ -399,7 +411,11 @@ static void _swift_release_n_(HeapObject *object, uint32_t n) { } void swift::swift_release_n(HeapObject *object, uint32_t n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_release_n(object, n); +#else CALL_IMPL(swift_release_n, (object, n)); +#endif } SWIFT_RUNTIME_EXPORT @@ -427,15 +443,22 @@ size_t swift::swift_weakRetainCount(HeapObject *object) { } HeapObject *swift::swift_unownedRetain(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return static_cast(swift_nonatomic_unownedRetain(object)); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain); if (!isValidPointerForNativeRetain(object)) return object; object->refCounts.incrementUnowned(1); return object; +#endif } void swift::swift_unownedRelease(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRelease(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease); if (!isValidPointerForNativeRetain(object)) return; @@ -450,6 +473,7 @@ void swift::swift_unownedRelease(HeapObject *object) { swift_slowDealloc(object, classMetadata->getInstanceSize(), classMetadata->getInstanceAlignMask()); } +#endif } void *swift::swift_nonatomic_unownedRetain(HeapObject *object) { @@ -479,15 +503,22 @@ void swift::swift_nonatomic_unownedRelease(HeapObject *object) { } HeapObject *swift::swift_unownedRetain_n(HeapObject *object, int n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_unownedRetain_n(object, n); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain_n); if (!isValidPointerForNativeRetain(object)) return object; object->refCounts.incrementUnowned(n); return object; +#endif } void swift::swift_unownedRelease_n(HeapObject *object, int n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRelease_n(object, n); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease_n); if (!isValidPointerForNativeRetain(object)) return; @@ -501,6 +532,7 @@ void swift::swift_unownedRelease_n(HeapObject *object, int n) { swift_slowDealloc(object, classMetadata->getInstanceSize(), classMetadata->getInstanceAlignMask()); } +#endif } HeapObject *swift::swift_nonatomic_unownedRetain_n(HeapObject *object, int n) { @@ -533,8 +565,13 @@ static HeapObject *_swift_tryRetain_(HeapObject *object) { if (!isValidPointerForNativeRetain(object)) return nullptr; +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + if (object->refCounts.tryIncrementNonAtomic()) return object; + else return nullptr; +#else if (object->refCounts.tryIncrement()) return object; else return nullptr; +#endif } HeapObject *swift::swift_tryRetain(HeapObject *object) { @@ -557,6 +594,9 @@ void swift::swift_setDeallocating(HeapObject *object) { } HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_unownedRetainStrong(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrong); if (!isValidPointerForNativeRetain(object)) return object; @@ -566,6 +606,7 @@ HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { if (! object->refCounts.tryIncrement()) swift::swift_abortRetainUnowned(object); return object; +#endif } HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { @@ -581,6 +622,9 @@ HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { } void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRetainStrongAndRelease(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrongAndRelease); if (!isValidPointerForNativeRetain(object)) return; @@ -594,6 +638,7 @@ void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { bool dealloc = object->refCounts.decrementUnownedShouldFree(1); assert(!dealloc && "retain-strong-and-release caused dealloc?"); (void) dealloc; +#endif } void swift::swift_nonatomic_unownedRetainStrongAndRelease(HeapObject *object) { From 102d6387d9b42ad13c4e66b6ef80469d606593bc Mon Sep 17 00:00:00 2001 From: Eric Miotto <1094986+edymtt@users.noreply.github.com> Date: Thu, 27 Aug 2020 10:25:51 -0700 Subject: [PATCH 385/663] [build] Don't execute dsymutil in parallel (#33654) `dsymutil` is already multithreaded and can be memory intensive -- execute it one at a time. Addresses rdar://63892559 --- utils/build-script-impl | 3 ++- utils/parser-lib/darwin-extract-symbols | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 078bca624b642..1e80510fa7ad2 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -2978,12 +2978,13 @@ for host in "${ALL_HOSTS[@]}"; do # # Exclude shell scripts and static archives. # Exclude swift-api-digester dSYM to reduce debug toolchain size. + # Run sequentially -- dsymutil is multithreaded and can be memory intensive (cd "${host_symroot}" && find ./"${CURRENT_PREFIX}" -perm -0111 -type f -print | \ grep -v '.py$' | \ grep -v '.a$' | \ grep -v 'swift-api-digester' | \ - xargs -n 1 -P ${BUILD_JOBS} ${dsymutil_path}) + xargs -n 1 -P 1 ${dsymutil_path}) # Strip executables, shared libraries and static libraries in # `host_install_destdir`. diff --git a/utils/parser-lib/darwin-extract-symbols b/utils/parser-lib/darwin-extract-symbols index a4ee1e4c61e96..1e10f61c7c11b 100755 --- a/utils/parser-lib/darwin-extract-symbols +++ b/utils/parser-lib/darwin-extract-symbols @@ -46,11 +46,12 @@ function xcrun_find_tool() { # Run dsymutil on executables and shared libraries. # # Exclude shell scripts. +# Run sequentially -- dsymutil is multithreaded and can be memory intensive (cd "${INSTALL_SYMROOT}" && find ./"${INSTALL_PREFIX}" -perm -0111 -type f -print | \ grep -v crashlog.py | \ grep -v symbolication.py | \ - xargs -n 1 -P ${BUILD_JOBS} $(xcrun_find_tool dsymutil)) + xargs -n 1 -P 1 $(xcrun_find_tool dsymutil)) # Strip executables, shared libraries and static libraries in INSTALL_DIR. find "${INSTALL_DIR}${INSTALL_PREFIX}/" \ From 1a44db3dcfc1302f0d9beaafe30ccbde8d31847d Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 27 Aug 2020 10:58:45 -0700 Subject: [PATCH 386/663] ABIChecker: exclude decls with the @_alwaysEmitIntoClient attribute Removing or updating @_alwaysEmitIntoClient functions are never ABI-breaking, thus we should exclude them from the symbol set for ABI stability checking. rdar://67883661 --- test/api-digester/Inputs/cake.swift | 3 +++ test/api-digester/Outputs/cake.json | 19 +++++++++++++++++++ .../ModuleAnalyzerNodes.cpp | 5 +++++ .../swift-api-digester/swift-api-digester.cpp | 17 ++++++++++++++--- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/test/api-digester/Inputs/cake.swift b/test/api-digester/Inputs/cake.swift index 3de399487412f..b1728b6f61d48 100644 --- a/test/api-digester/Inputs/cake.swift +++ b/test/api-digester/Inputs/cake.swift @@ -139,3 +139,6 @@ public class UnavailableOnMac {} extension SwiftObjcClass { public func functionUnavailableOnMac() {} } + +@_alwaysEmitIntoClient +public func emitIntoClientFunc() {} diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json index 8a487febb665b..08a230436a852 100644 --- a/test/api-digester/Outputs/cake.json +++ b/test/api-digester/Outputs/cake.json @@ -1340,6 +1340,25 @@ ], "hasMissingDesignatedInitializers": true }, + { + "kind": "Function", + "name": "emitIntoClientFunc", + "printedName": "emitIntoClientFunc()", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + } + ], + "declKind": "Func", + "usr": "s:4cake18emitIntoClientFuncyyF", + "moduleName": "cake", + "declAttributes": [ + "AlwaysEmitIntoClient" + ], + "funcSelfKind": "NonMutating" + }, { "kind": "TypeDecl", "name": "Int", diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp index 9e91584e84659..813a7bd843097 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp @@ -1603,6 +1603,11 @@ SDKContext::shouldIgnore(Decl *D, const Decl* Parent) const { if (isa(VD)) return true; } + // Exclude decls with @_alwaysEmitIntoClient if we are checking ABI. + // These decls are considered effectively public because they are usable + // from inline, so we have to manually exclude them here. + if (D->getAttrs().hasAttribute()) + return true; } else { if (D->isPrivateStdlibDecl(false)) return true; diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index 2b089bf718c5f..deb532fd8e162 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -1057,6 +1057,17 @@ void swift::ide::api::SDKNodeTypeFunc::diagnose(SDKNode *Right) { } namespace { +static void diagnoseRemovedDecl(const SDKNodeDecl *D) { + if (D->getSDKContext().checkingABI()) { + // Don't complain about removing @_alwaysEmitIntoClient if we are checking ABI. + // We shouldn't include these decls in the ABI baseline file. This line is + // added so the checker is backward compatible. + if (D->hasDeclAttribute(DeclAttrKind::DAK_AlwaysEmitIntoClient)) + return; + } + D->emitDiag(SourceLoc(), diag::removed_decl, D->isDeprecated()); +} + // This is first pass on two given SDKNode trees. This pass removes the common part // of two versions of SDK, leaving only the changed part. class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { @@ -1241,7 +1252,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { TD->isProtocol()); } if (auto *Acc = dyn_cast(Left)) { - Acc->emitDiag(SourceLoc(), diag::removed_decl, Acc->isDeprecated()); + diagnoseRemovedDecl(Acc); } return; case NodeMatchReason::FuncToProperty: @@ -2084,7 +2095,7 @@ static bool diagnoseRemovedExtensionMembers(const SDKNode *Node) { if (DT->isExtension()) { for (auto *C: DT->getChildren()) { auto *MD = cast(C); - MD->emitDiag(SourceLoc(), diag::removed_decl, MD->isDeprecated()); + diagnoseRemovedDecl(MD); } return true; } @@ -2161,7 +2172,7 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) { } bool handled = diagnoseRemovedExtensionMembers(Node); if (!handled) - Node->emitDiag(SourceLoc(), diag::removed_decl, Node->isDeprecated()); + diagnoseRemovedDecl(Node); return; } case NodeAnnotation::Rename: { From 524cfae1b29a96b29dc9ea5d2e68cd46702af5e5 Mon Sep 17 00:00:00 2001 From: tbkka Date: Thu, 27 Aug 2020 11:06:40 -0700 Subject: [PATCH 387/663] [Dynamic Casting] Overhauled Runtime (#33561) * Dynamic Cast Rework: Runtime This is a completely refactored version of the core swift_dynamicCast runtime method. This fixes a number of bugs, especially in the handling of multiply-wrapped types such as Optional within Any. The result should be much closer to the behavior specified by `docs/DynamicCasting.md`. Most of the type-specific logic is simply copied over from the earlier implementation, but the overall structure has been changed to be uniformly recursive. In particular, this provides uniform handling of Optional, existentials, Any and other common "box" types along all paths. The consistent structure should also be easier to update in the future with new general types. Benchmarking does not show any noticable performance implications. **Temporarily**, the old implementation is still available. Setting the environment variable `SWIFT_OLD_DYNAMIC_CAST_RUNTIME` before launching a program will use the old runtime implementation. This is only to facilitate testing; once the new implementation is stable, I expect to completely remove the old implementation. --- stdlib/public/core/DebuggerSupport.swift | 9 +- stdlib/public/runtime/CMakeLists.txt | 1 + stdlib/public/runtime/Casting.cpp | 58 +- .../public/runtime/CompatibilityOverride.def | 17 +- stdlib/public/runtime/DynamicCast.cpp | 2197 +++++++++++++++++ test/{stdlib => Casting}/CastTraps.swift.gyb | 54 +- test/Casting/Casts.swift | 763 ++++++ .../SDK/protocol_lookup_foreign.swift | 58 +- test/Interpreter/tuple_casts.swift | 28 +- test/stdlib/Casts.swift | 236 -- validation-test/Casting/BoxingCasts.swift.gyb | 264 ++ 11 files changed, 3417 insertions(+), 268 deletions(-) create mode 100644 stdlib/public/runtime/DynamicCast.cpp rename test/{stdlib => Casting}/CastTraps.swift.gyb (61%) create mode 100644 test/Casting/Casts.swift delete mode 100644 test/stdlib/Casts.swift create mode 100644 validation-test/Casting/BoxingCasts.swift.gyb diff --git a/stdlib/public/core/DebuggerSupport.swift b/stdlib/public/core/DebuggerSupport.swift index 0e7095aebd783..82cfedd5eb4fb 100644 --- a/stdlib/public/core/DebuggerSupport.swift +++ b/stdlib/public/core/DebuggerSupport.swift @@ -152,7 +152,14 @@ public enum _DebuggerSupport { // yes, a type can lie and say it's a class when it's not since we only // check the displayStyle - but then the type would have a custom Mirror // anyway, so there's that... - let willExpand = mirror.displayStyle != .`class` || value is CustomReflectable? + let isNonClass = mirror.displayStyle != .`class` + let isCustomReflectable: Bool + if let value = value { + isCustomReflectable = value is CustomReflectable + } else { + isCustomReflectable = true + } + let willExpand = isNonClass || isCustomReflectable let count = mirror._children.count let bullet = isRoot && (count == 0 || !willExpand) ? "" diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index e29be3ff2033e..0b481bd2459b8 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -33,6 +33,7 @@ set(swift_runtime_sources CompatibilityOverride.cpp CygwinPort.cpp Demangle.cpp + DynamicCast.cpp Enum.cpp EnvironmentVariables.cpp ErrorObjectCommon.cpp diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 6db0739a585ed..99e08243588bb 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -339,6 +339,15 @@ _dynamicCastClassMetatype(const ClassMetadata *sourceType, return nullptr; } +#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_unboxFromSwiftValueWithType(OpaqueValue *source, + OpaqueValue *result, + const Metadata *destinationType); +/// Nominal type descriptor for Swift.__SwiftValue +extern "C" const ClassDescriptor NOMINAL_TYPE_DESCR_SYM(s12__SwiftValueC); +#endif + /// Dynamically cast a class instance to a Swift class type. static const void *swift_dynamicCastClassImpl(const void *object, const ClassMetadata *targetType) { @@ -351,10 +360,28 @@ static const void *swift_dynamicCastClassImpl(const void *object, } #endif - auto isa = _swift_getClassOfAllocated(object); + auto srcType = _swift_getClassOfAllocated(object); - if (_dynamicCastClassMetatype(isa, targetType)) + if (_dynamicCastClassMetatype(srcType, targetType)) return object; + +#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class on Linux + if (srcType->getKind() == MetadataKind::Class + && targetType->getKind() == MetadataKind::Class) { + auto srcClassType = cast(srcType); + auto srcDescr = srcClassType->getDescription(); + if (srcDescr == &NOMINAL_TYPE_DESCR_SYM(s12__SwiftValueC)) { + auto srcValue = reinterpret_cast(&object); + void *result; + auto destLocation = reinterpret_cast(&result); + if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, targetType)) { + swift_unknownObjectRelease(const_cast(object)); + return result; + } + } + } +#endif + return nullptr; } @@ -3262,3 +3289,30 @@ HeapObject *_swift_bridgeToObjectiveCUsingProtocolIfPossible( #define OVERRIDE_CASTING COMPATIBILITY_OVERRIDE #include "CompatibilityOverride.def" +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX + +// A way for the new implementation to call the old one, so we +// can support switching between the two until the new one is +// fully settled. + +// XXX TODO XXX Once the new implementation is stable, remove the following, +// swift_dynamicCastImpl above, and all the other code above that only exists to +// support that. (Don't forget _dynamicCastToExistential!!) This file should +// be only ~1400 lines when you're done. + +extern "C" { + bool swift_dynamicCast_OLD(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags) + { + return swift_dynamicCastImpl(destLocation, srcValue, srcType, destType, flags); + } +} + +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX diff --git a/stdlib/public/runtime/CompatibilityOverride.def b/stdlib/public/runtime/CompatibilityOverride.def index 92e32430251cd..40f6a055b3857 100644 --- a/stdlib/public/runtime/CompatibilityOverride.def +++ b/stdlib/public/runtime/CompatibilityOverride.def @@ -40,6 +40,7 @@ #ifdef OVERRIDE # define OVERRIDE_METADATALOOKUP OVERRIDE # define OVERRIDE_CASTING OVERRIDE +# define OVERRIDE_DYNAMICCASTING OVERRIDE # define OVERRIDE_OBJC OVERRIDE # define OVERRIDE_FOREIGN OVERRIDE # define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE @@ -52,6 +53,9 @@ # ifndef OVERRIDE_CASTING # define OVERRIDE_CASTING(...) # endif +# ifndef OVERRIDE_DYNAMICCASTING +# define OVERRIDE_DYNAMICCASTING(...) +# endif # ifndef OVERRIDE_OBJC # define OVERRIDE_OBJC(...) # endif @@ -69,12 +73,12 @@ # endif #endif -OVERRIDE_CASTING(dynamicCast, bool, , , swift::, - (OpaqueValue *dest, OpaqueValue *src, - const Metadata *srcType, - const Metadata *targetType, - DynamicCastFlags flags), - (dest, src, srcType, targetType, flags)) +OVERRIDE_DYNAMICCASTING(dynamicCast, bool, , , swift::, + (OpaqueValue *dest, OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags), + (dest, src, srcType, targetType, flags)) OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, @@ -212,6 +216,7 @@ OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift:: #undef OVERRIDE #undef OVERRIDE_METADATALOOKUP #undef OVERRIDE_CASTING +#undef OVERRIDE_DYNAMICCASTING #undef OVERRIDE_OBJC #undef OVERRIDE_FOREIGN #undef OVERRIDE_PROTOCOLCONFORMANCE diff --git a/stdlib/public/runtime/DynamicCast.cpp b/stdlib/public/runtime/DynamicCast.cpp new file mode 100644 index 0000000000000..fa628e296fb2a --- /dev/null +++ b/stdlib/public/runtime/DynamicCast.cpp @@ -0,0 +1,2197 @@ +//===--- DynamicCast.cpp - Swift Language Dynamic Casting Support ---------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Implementations of the dynamic cast runtime functions. +// +//===----------------------------------------------------------------------===// + +#include "CompatibilityOverride.h" +#include "ErrorObject.h" +#include "Private.h" +#include "SwiftHashableSupport.h" +#include "swift/ABI/MetadataValues.h" +#include "swift/Basic/Lazy.h" +#include "swift/Runtime/Casting.h" +#include "swift/Runtime/Config.h" +#include "swift/Runtime/ExistentialContainer.h" +#include "swift/Runtime/HeapObject.h" +#if SWIFT_OBJC_INTEROP +#include "swift/Runtime/ObjCBridge.h" +#include "SwiftObject.h" +#include "SwiftValue.h" +#endif + +using namespace swift; +using namespace hashable_support; + +// +// The top-level driver code directly handles the most general cases +// (identity casts, _ObjectiveCBridgeable, _SwiftValue boxing) and +// recursively unwraps source and/or destination as appropriate. +// It calls "tryCastToXyz" functions to perform tailored operations +// for a particular destination type. +// +// For each kind of destination, there is a "tryCastToXyz" that +// accepts a source value and attempts to fit it into a destination +// storage location. This function should assume that: +// * The source and destination types are _not_ identical. +// * The destination is of the expected type. +// * The source is already fully unwrapped. If the source is an +// Existential or Optional that you cannot handle directly, do _not_ +// try to unwrap it. Just return failure and you will get called +// again with the unwrapped source. +// +// Each such function accepts the following arguments: +// * Destination location and type +// * Source value address and type +// * References to the types that will be used to report failure. +// The function can update these with specific failing types +// to improve the reported failure. +// * Bool indicating whether the compiler has asked us to "take" the +// value instead of copying. +// * Bool indicating whether it's okay to do type checks lazily on later +// access (this is permitted only for unconditional casts that will +// abort the program on failure anyway). +// +// The return value is one of the following: +// * Failure. In this case, the tryCastFunction should do nothing; your +// caller will either try another strategy or report the failure and +// do any necessary cleanup. +// * Success via "copy". You successfully copied the source value. +// * Success via "take". If "take" was requested and you can do so cheaply, +// perform the take and return SuccessViaTake. If "take" is not cheap, you +// should copy and return SuccessViaCopy. Top-level code will detect this +// and take care of destroying the source for you. +// +enum class DynamicCastResult { + Failure, /// The cast attempt "failed" (did nothing). + SuccessViaCopy, /// Cast succeeded, source is still valid. + SuccessViaTake, /// Cast succeeded, source is invalid +}; +static bool isSuccess(DynamicCastResult result) { + return result != DynamicCastResult::Failure; +} + +// All of our `tryCastXyz` functions have the following signature. +typedef DynamicCastResult (tryCastFunctionType)( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks +); + +// Forward-declare the main top-level `tryCast()` function +static tryCastFunctionType tryCast; + +/// Nominal type descriptor for Swift.AnyHashable +extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s11AnyHashable); + +/// Nominal type descriptor for Swift.__SwiftValue +//extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s12__SwiftValue); + +/// Nominal type descriptor for Swift.Array. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sa); + +/// Nominal type descriptor for Swift.Dictionary. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SD); + +/// Nominal type descriptor for Swift.Set. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sh); + +/// Nominal type descriptor for Swift.String. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS); + +static HeapObject * getNonNullSrcObject(OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType) { + auto object = *reinterpret_cast(srcValue); + if (LLVM_LIKELY(object != nullptr)) { + return object; + } + + std::string srcTypeName = nameForMetadata(srcType); + std::string destTypeName = nameForMetadata(destType); + swift::fatalError(/* flags = */ 0, + "Found unexpected null pointer value" + " while trying to cast value of type '%s' (%p)" + " to '%s' (%p)\n", + srcTypeName.c_str(), srcType, + destTypeName.c_str(), destType); +} + +/******************************************************************************/ +/******************************* Bridge Helpers *******************************/ +/******************************************************************************/ + +#define _bridgeAnythingToObjectiveC \ + MANGLE_SYM(s27_bridgeAnythingToObjectiveCyyXlxlF) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API +HeapObject *_bridgeAnythingToObjectiveC( + OpaqueValue *src, const Metadata *srcType); + +#if SWIFT_OBJC_INTEROP +SWIFT_RUNTIME_EXPORT +id swift_dynamicCastMetatypeToObjectConditional(const Metadata *metatype); +#endif + +// protocol _ObjectiveCBridgeable { +struct _ObjectiveCBridgeableWitnessTable : WitnessTable { + static_assert(WitnessTableFirstRequirementOffset == 1, + "Witness table layout changed"); + + // associatedtype _ObjectiveCType : class + void *_ObjectiveCType; + + // func _bridgeToObjectiveC() -> _ObjectiveCType + SWIFT_CC(swift) + HeapObject *(*bridgeToObjectiveC)( + SWIFT_CONTEXT OpaqueValue *self, const Metadata *Self, + const _ObjectiveCBridgeableWitnessTable *witnessTable); + + // class func _forceBridgeFromObjectiveC(x: _ObjectiveCType, + // inout result: Self?) + SWIFT_CC(swift) + void (*forceBridgeFromObjectiveC)( + HeapObject *sourceValue, + OpaqueValue *result, + SWIFT_CONTEXT const Metadata *self, + const Metadata *selfType, + const _ObjectiveCBridgeableWitnessTable *witnessTable); + + // class func _conditionallyBridgeFromObjectiveC(x: _ObjectiveCType, + // inout result: Self?) -> Bool + SWIFT_CC(swift) + bool (*conditionallyBridgeFromObjectiveC)( + HeapObject *sourceValue, + OpaqueValue *result, + SWIFT_CONTEXT const Metadata *self, + const Metadata *selfType, + const _ObjectiveCBridgeableWitnessTable *witnessTable); +}; +// } + +extern "C" const ProtocolDescriptor +PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable); + +static const _ObjectiveCBridgeableWitnessTable * +findBridgeWitness(const Metadata *T) { + static const auto bridgeableProtocol + = &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable); + auto w = swift_conformsToProtocol(T, bridgeableProtocol); + return reinterpret_cast(w); +} + +/// Retrieve the bridged Objective-C type for the given type that +/// conforms to \c _ObjectiveCBridgeable. +MetadataResponse +_getBridgedObjectiveCType( + MetadataRequest request, + const Metadata *conformingType, + const _ObjectiveCBridgeableWitnessTable *wtable) +{ + // FIXME: Can we directly reference the descriptor somehow? + const ProtocolConformanceDescriptor *conformance = wtable->getDescription(); + const ProtocolDescriptor *protocol = conformance->getProtocol(); + auto assocTypeRequirement = protocol->getRequirements().begin(); + assert(assocTypeRequirement->Flags.getKind() == + ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction); + auto mutableWTable = (WitnessTable *)wtable; + return swift_getAssociatedTypeWitness( + request, mutableWTable, conformingType, + protocol->getRequirementBaseDescriptor(), + assocTypeRequirement); +} + +/// Dynamic cast from a class type to a value type that conforms to the +/// _ObjectiveCBridgeable, first by dynamic casting the object to the +/// class to which the value type is bridged, and then bridging +/// from that object to the value type via the witness table. +/// +/// Caveat: Despite the name, this is also used to bridge pure Swift +/// classes to Swift value types even when Obj-C is not being used. + +static DynamicCastResult +_tryCastFromClassToObjCBridgeable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, void *srcObject, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks, + const _ObjectiveCBridgeableWitnessTable *destBridgeWitness, + const Metadata *targetBridgeClass) +{ + + // 2. Allocate a T? to receive the bridge result. + + // The extra byte is for the tag. + auto targetSize = destType->getValueWitnesses()->getSize() + 1; + auto targetAlignMask = destType->getValueWitnesses()->getAlignmentMask(); + + // Object that frees a buffer when it goes out of scope. + struct FreeBuffer { + void *Buffer = nullptr; + size_t size, alignMask; + FreeBuffer(size_t size, size_t alignMask) : + size(size), alignMask(alignMask) {} + + ~FreeBuffer() { + if (Buffer) + swift_slowDealloc(Buffer, size, alignMask); + } + } freeBuffer{targetSize, targetAlignMask}; + + // The extra byte is for the tag on the T? + const std::size_t inlineValueSize = 3 * sizeof(void*); + alignas(std::max_align_t) char inlineBuffer[inlineValueSize + 1]; + void *optDestBuffer; + if (destType->getValueWitnesses()->getStride() <= inlineValueSize) { + // Use the inline buffer. + optDestBuffer = inlineBuffer; + } else { + // Allocate a buffer. + optDestBuffer = swift_slowAlloc(targetSize, targetAlignMask); + freeBuffer.Buffer = optDestBuffer; + } + + // Initialize the buffer as an empty optional. + destType->vw_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer, + 1, 1); + + // 3. Bridge into the T? (Effectively a copy operation.) + bool success; + if (mayDeferChecks) { + destBridgeWitness->forceBridgeFromObjectiveC( + (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, + destType, destType, destBridgeWitness); + success = true; + } else { + success = destBridgeWitness->conditionallyBridgeFromObjectiveC( + (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, + destType, destType, destBridgeWitness); + } + + // If we succeeded, then take the value from the temp buffer. + if (success) { + destType->vw_initializeWithTake(destLocation, (OpaqueValue *)optDestBuffer); + // Bridge above is effectively a copy, so overall we're a copy. + return DynamicCastResult::SuccessViaCopy; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastFromClassToObjCBridgeable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + // We need the _ObjectiveCBridgeable conformance for the target + auto destBridgeWitness = findBridgeWitness(destType); + if (destBridgeWitness == nullptr) { + return DynamicCastResult::Failure; + } + + // 1. Sanity check whether the source object can cast to the + // type expected by the target. + + auto targetBridgedClass = + _getBridgedObjectiveCType(MetadataState::Complete, destType, + destBridgeWitness).Value; + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (nullptr == swift_dynamicCastUnknownClass(srcObject, targetBridgedClass)) { + destFailureType = targetBridgedClass; + return DynamicCastResult::Failure; + } + + return _tryCastFromClassToObjCBridgeable( + destLocation, destType, + srcValue, srcType, srcObject, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks, + destBridgeWitness, targetBridgedClass); +} + +/// Dynamic cast from a value type that conforms to the +/// _ObjectiveCBridgeable protocol to a class type, first by bridging +/// the value to its Objective-C object representation and then by +/// dynamic casting that object to the resulting target type. +/// +/// Caveat: Despite the name, this is also used to bridge Swift value types +/// to Swift classes even when Obj-C is not being used. +static DynamicCastResult +tryCastFromObjCBridgeableToClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + auto srcBridgeWitness = findBridgeWitness(srcType); + if (srcBridgeWitness == nullptr) { + return DynamicCastResult::Failure; + } + + // Bridge the source value to an object. + auto srcBridgedObject = + srcBridgeWitness->bridgeToObjectiveC(srcValue, srcType, srcBridgeWitness); + + // Dynamic cast the object to the resulting class type. + if (auto cast = swift_dynamicCastUnknownClass(srcBridgedObject, destType)) { + *reinterpret_cast(destLocation) = cast; + return DynamicCastResult::SuccessViaCopy; + } else { + // We don't need the object anymore. + swift_unknownObjectRelease(srcBridgedObject); + return DynamicCastResult::Failure; + } +} + +/******************************************************************************/ +/****************************** SwiftValue Boxing *****************************/ +/******************************************************************************/ + +#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_unboxFromSwiftValueWithType(OpaqueValue *source, + OpaqueValue *result, + const Metadata *destinationType); + +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_swiftValueConformsTo(const Metadata *, const Metadata *); +#endif + +#if SWIFT_OBJC_INTEROP +// Try unwrapping a source holding an Obj-C SwiftValue container and +// recursively casting the contents. +static DynamicCastResult +tryCastUnwrappingObjCSwiftValueSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + id srcObject; + memcpy(&srcObject, srcValue, sizeof(id)); + auto srcSwiftValue = getAsSwiftValue(srcObject); + + if (srcSwiftValue == nullptr) { + return DynamicCastResult::Failure; + } + + const Metadata *srcInnerType; + const OpaqueValue *srcInnerValue; + std::tie(srcInnerType, srcInnerValue) + = getValueFromSwiftValue(srcSwiftValue); + // Note: We never `take` the contents from a SwiftValue box as + // it might have other references. Instead, let our caller + // destroy the reference if necessary. + return tryCast( + destLocation, destType, + const_cast(srcInnerValue), srcInnerType, + destFailureType, srcFailureType, + /*takeOnSuccess=*/ false, mayDeferChecks); +} +#endif + +/******************************************************************************/ +/****************************** Class Destination *****************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToSwiftClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Class); + + auto destClassType = cast(destType); + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => Swift class + case MetadataKind::ObjCClassWrapper: { // Obj-C class => Swift class + void *object = getNonNullSrcObject(srcValue, srcType, destType); + if (auto t = swift_dynamicCastClass(object, destClassType)) { + auto castObject = const_cast(t); + *(reinterpret_cast(destLocation)) = castObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(castObject); + return DynamicCastResult::SuccessViaCopy; + } + } else { + srcFailureType = srcType; + destFailureType = destType; + return DynamicCastResult::Failure; + } + } + + case MetadataKind::ForeignClass: // CF class => Swift class + // Top-level code will "unwrap" to an Obj-C class and try again. + return DynamicCastResult::Failure; + + default: + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToObjectiveCClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ObjCClassWrapper); +#if SWIFT_OBJC_INTEROP + auto destObjCType = cast(destType); + + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => Obj-C class + case MetadataKind::ObjCClassWrapper: // Obj-C class => Obj-C class + case MetadataKind::ForeignClass: { // CF class => Obj-C class + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + auto destObjCClass = destObjCType->Class; + if (auto resultObject + = swift_dynamicCastObjCClass(srcObject, destObjCClass)) { + *reinterpret_cast(destLocation) = resultObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + objc_retain((id)const_cast(resultObject)); + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + + default: + break; + } +#endif + + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToForeignClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ +#if SWIFT_OBJC_INTEROP + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ForeignClass); + auto destClassType = cast(destType); + + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => CF class + case MetadataKind::ObjCClassWrapper: // Obj-C class => CF class + case MetadataKind::ForeignClass: { // CF class => CF class + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (auto resultObject + = swift_dynamicCastForeignClass(srcObject, destClassType)) { + *reinterpret_cast(destLocation) = resultObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + objc_retain((id)const_cast(resultObject)); + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + default: + break; + } +#endif + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/***************************** Enum Destination *******************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToEnum( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + // Note: Optional is handled elsewhere + assert(destType->getKind() == MetadataKind::Enum); + + // Enum has no special cast support at present. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/**************************** Struct Destination ******************************/ +/******************************************************************************/ + +// internal func _arrayDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_arrayDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType); + +// internal func _arrayDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_arrayDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType); + +// internal func _setDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_setDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType, + const void *sourceValueHashable, + const void *targetValueHashable); + +// internal func _setDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_setDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType, + const void *sourceValueHashable, + const void *targetValueHashable); + +// internal func _dictionaryDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_dictionaryDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceKeyType, + const Metadata *sourceValueType, + const Metadata *targetKeyType, + const Metadata *targetValueType, + const void *sourceKeyHashable, + const void *targetKeyHashable); + +// internal func _dictionaryDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_dictionaryDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceKeyType, + const Metadata *sourceValueType, + const Metadata *targetKeyType, + const Metadata *targetValueType, + const void *sourceKeyHashable, + const void *targetKeyHashable); + +#if SWIFT_OBJC_INTEROP +// Helper to memoize bridging conformance data for a particular +// Swift struct type. This is used to speed up the most common +// ObjC->Swift bridging conversions by eliminating repeeated +// protocol conformance lookups. + +// Currently used only for String, which may be the only +// type used often enough to justify the extra static memory. +struct ObjCBridgeMemo { +#if !NDEBUG + // Used in assert build to verify that we always get called with + // the same destType + const Metadata *destType; +#endif + const _ObjectiveCBridgeableWitnessTable *destBridgeWitness; + const Metadata *targetBridgedType; + Class targetBridgedObjCClass; + swift_once_t fetchWitnessOnce; + + DynamicCastResult tryBridge( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) + { + struct SetupData { + const Metadata *destType; + struct ObjCBridgeMemo *memo; + } setupData { destType, this }; + + swift_once(&fetchWitnessOnce, + [](void *data) { + struct SetupData *setupData = (struct SetupData *)data; + struct ObjCBridgeMemo *memo = setupData->memo; +#if !NDEBUG + memo->destType = setupData->destType; +#endif + memo->destBridgeWitness = findBridgeWitness(setupData->destType); + if (memo->destBridgeWitness == nullptr) { + memo->targetBridgedType = nullptr; + memo->targetBridgedObjCClass = nullptr; + } else { + memo->targetBridgedType = _getBridgedObjectiveCType( + MetadataState::Complete, setupData->destType, memo->destBridgeWitness).Value; + assert(memo->targetBridgedType->getKind() == MetadataKind::ObjCClassWrapper); + memo->targetBridgedObjCClass = memo->targetBridgedType->getObjCClassObject(); + assert(memo->targetBridgedObjCClass != nullptr); + } + }, (void *)&setupData); + + // Check that this always gets called with the same destType. + assert((destType == this->destType) && "ObjC casting memo used inconsistently"); + + // !! If bridging is not usable, stop here. + if (targetBridgedObjCClass == nullptr) { + return DynamicCastResult::Failure; + } + // Use the dynamic ISA type of the object always (Note that this + // also implicitly gives us the ObjC type for a CF object.) + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + Class srcObjCType = object_getClass((id)srcObject); + // Fail if the ObjC object is not a subclass of the bridge class. + while (srcObjCType != targetBridgedObjCClass) { + srcObjCType = class_getSuperclass(srcObjCType); + if (srcObjCType == nullptr) { + return DynamicCastResult::Failure; + } + } + // The ObjC object is an acceptable type, so call the bridge function... + return _tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, srcObject, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks, + destBridgeWitness, targetBridgedType); + } +}; +#endif + +static DynamicCastResult +tryCastToAnyHashable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)); + + auto hashableConformance = reinterpret_cast( + swift_conformsToProtocol(srcType, &HashableProtocolDescriptor)); + if (hashableConformance) { + _swift_convertToAnyHashableIndirect(srcValue, destLocation, + srcType, hashableConformance); + return DynamicCastResult::SuccessViaCopy; + } else { + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToArray( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(Sa)); + + switch (srcType->getKind()) { + case MetadataKind::Struct: { // Struct -> Array + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(Sa)) { // Array -> Array + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_arrayDownCastIndirect( + srcValue, destLocation, sourceArgs[0], destArgs[0]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_arrayDownCastConditionalIndirect( + srcValue, destLocation, sourceArgs[0], destArgs[0]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToDictionary( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(SD)); + + switch (srcType->getKind()) { + case MetadataKind::Struct: { // Struct -> Dictionary + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(SD)) { // Dictionary -> Dictionary + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_dictionaryDownCastIndirect( + srcValue, destLocation, sourceArgs[0], sourceArgs[1], + destArgs[0], destArgs[1], sourceArgs[2], destArgs[2]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_dictionaryDownCastConditionalIndirect( + srcValue, destLocation, sourceArgs[0], sourceArgs[1], + destArgs[0], destArgs[1], sourceArgs[2], destArgs[2]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToSet( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(Sh)); + + switch (srcType->getKind()) { + + case MetadataKind::Struct: { // Struct -> Set + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(Sh)) { // Set -> Set + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_setDownCastIndirect(srcValue, destLocation, + sourceArgs[0], destArgs[0], sourceArgs[1], destArgs[1]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_setDownCastConditionalIndirect( + srcValue, destLocation, + sourceArgs[0], destArgs[0], + sourceArgs[1], destArgs[1]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToString( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(SS)); + + switch (srcType->getKind()) { + case MetadataKind::ForeignClass: // CF -> String + case MetadataKind::ObjCClassWrapper: { // Obj-C -> String +#if SWIFT_OBJC_INTEROP + static ObjCBridgeMemo memo; + return memo.tryBridge( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks); +#endif + } + default: + return DynamicCastResult::Failure; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToStruct( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + + // There is no special cast handling at present for general Struct types. + + // Special logic for AnyHashable, Set, Dictionary, Array, and String + // is broken out above. See also selectCasterForDest() for the + // logic that chooses one of these functions. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/*************************** Optional Destination *****************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToOptional( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Optional); + + // Nothing to do for the basic casting operation. + // Unwrapping is handled by top-level tryCast with assistance + // from utility functions below. + + return DynamicCastResult::Failure; +} + +// The nil value `T?.none` can be cast to any optional type. +// When the unwrapper sees a source value that is nil, it calls +// tryCastFromNil() to try to set the target optional to nil. +// +// This is complicated by the desire to preserve the nesting +// as far as possible. For example, we would like: +// Int?.none => Int??.some(.none) +// Int??.none => Any????.some(.some(.none)) +// Of course, if the target is shallower than the source, +// then we have to just set the outermost optional to nil. + +// This helper sets a nested optional to nil at a requested level: +static void +initializeToNilAtDepth(OpaqueValue *destLocation, const Metadata *destType, int depth) { + assert(destType->getKind() == MetadataKind::Optional); + auto destInnerType = cast(destType)->getGenericArgs()[0]; + if (depth > 0) { + initializeToNilAtDepth(destLocation, destInnerType, depth - 1); + // Set .some at each level as we unwind + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, 0, 1); + } else { + // Set .none at the lowest level + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, 1, 1); + } +} + +static void +copyNil(OpaqueValue *destLocation, const Metadata *destType, const Metadata *srcType) +{ + assert(srcType->getKind() == MetadataKind::Optional); + assert(destType->getKind() == MetadataKind::Optional); + + // Measure how deep the source nil is: Is it Int?.none or Int??.none or ... + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + int srcDepth = 1; + while (srcInnerType->getKind() == MetadataKind::Optional) { + srcInnerType = cast(srcInnerType)->getGenericArgs()[0]; + srcDepth += 1; + } + + // Measure how deep the destination optional is + auto destInnerType = cast(destType)->getGenericArgs()[0]; + int destDepth = 1; + while (destInnerType->getKind() == MetadataKind::Optional) { + destInnerType = cast(destInnerType)->getGenericArgs()[0]; + destDepth += 1; + } + + // Recursively set the destination to .some(.some(... .some(.none))) + auto targetDepth = std::max(destDepth - srcDepth, 0); + initializeToNilAtDepth(destLocation, destType, targetDepth); +} + +// Try unwrapping both source and dest optionals together. +// If the source is nil, then cast that to the destination. +static DynamicCastResult +tryCastUnwrappingOptionalBoth( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(destType->getKind() == MetadataKind::Optional); + assert(srcType->getKind() == MetadataKind::Optional); + + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload( + srcValue, /*emptyCases=*/1); + auto sourceIsNil = (sourceEnumCase != 0); + if (sourceIsNil) { + copyNil(destLocation, destType, srcType); + return DynamicCastResult::SuccessViaCopy; // nil was essentially copied to dest + } else { + auto destEnumType = cast(destType); + const Metadata *destInnerType = destEnumType->getGenericArgs()[0]; + auto destInnerLocation = destLocation; // Single-payload enum layout + auto subcastResult = tryCast( + destInnerLocation, destInnerType, srcValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, /*case*/ 0, /*emptyCases*/ 1); + } + return subcastResult; + } + return DynamicCastResult::Failure; +} + +// Try unwrapping just the destination optional. +// Note we do this even if both src and dest are optional. +// For example, Int -> Any? requires unwrapping the destination +// in order to inject the Int into the existential. +static DynamicCastResult +tryCastUnwrappingOptionalDestination( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(destType->getKind() == MetadataKind::Optional); + + auto destEnumType = cast(destType); + const Metadata *destInnerType = destEnumType->getGenericArgs()[0]; + auto destInnerLocation = destLocation; // Single-payload enum layout + auto subcastResult = tryCast( + destInnerLocation, destInnerType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, /*case*/ 0, /*emptyCases*/ 1); + } + return subcastResult; +} + +// Try unwrapping just the source optional. +// Note we do this even if both target and dest are optional. +// For example, this is used when extracting the contents of +// an Optional. +static DynamicCastResult +tryCastUnwrappingOptionalSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType->getKind() == MetadataKind::Optional); + + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload( + srcValue, /*emptyCases=*/1); + auto nonNil = (sourceEnumCase == 0); + if (nonNil) { + // Recurse with unwrapped source + return tryCast(destLocation, destType, srcValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/***************************** Tuple Destination ******************************/ +/******************************************************************************/ + +// The only thing that can be legally cast to a tuple is another tuple. +// Most of the logic below is required to handle element-wise casts of +// tuples that are compatible but not of the same type. + +static DynamicCastResult +tryCastToTuple( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Tuple); + const auto destTupleType = cast(destType); + + srcFailureType = srcType; + destFailureType = destType; + + // We cannot cast non-tuple data to a tuple + if (srcType->getKind() != MetadataKind::Tuple) { + return DynamicCastResult::Failure; + } + const auto srcTupleType = cast(srcType); + + // Tuples must have same number of elements + if (srcTupleType->NumElements != destTupleType->NumElements) { + return DynamicCastResult::Failure; + } + + // Common labels must match + const char *srcLabels = srcTupleType->Labels; + const char *destLabels = destTupleType->Labels; + while (srcLabels != nullptr + && destLabels != nullptr + && srcLabels != destLabels) + { + const char *srcSpace = strchr(srcLabels, ' '); + const char *destSpace = strchr(destLabels, ' '); + + // If we've reached the end of either label string, we're done. + if (srcSpace == nullptr || destSpace == nullptr) { + break; + } + + // If both labels are non-empty, and the labels mismatch, we fail. + if (srcSpace != srcLabels && destSpace != destLabels) { + unsigned srcLen = srcSpace - srcLabels; + unsigned destLen = destSpace - destLabels; + if (srcLen != destLen || + strncmp(srcLabels, destLabels, srcLen) != 0) + return DynamicCastResult::Failure; + } + + srcLabels = srcSpace + 1; + destLabels = destSpace + 1; + } + + // Compare the element types to see if they all match. + bool typesMatch = true; + auto numElements = srcTupleType->NumElements; + for (unsigned i = 0; typesMatch && i != numElements; ++i) { + if (srcTupleType->getElement(i).Type != destTupleType->getElement(i).Type) { + typesMatch = false; + } + } + + if (typesMatch) { + // The actual element types are identical, so we can use the + // fast value-witness machinery for the whole tuple. + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } + } else { + // Slow path casts each item separately. + for (unsigned j = 0, n = srcTupleType->NumElements; j != n; ++j) { + const auto &srcElt = srcTupleType->getElement(j); + const auto &destElt = destTupleType->getElement(j); + auto subcastResult = tryCast(destElt.findIn(destLocation), destElt.Type, + srcElt.findIn(srcValue), srcElt.Type, + destFailureType, srcFailureType, + false, mayDeferChecks); + if (subcastResult == DynamicCastResult::Failure) { + for (unsigned k = 0; k != j; ++k) { + const auto &elt = destTupleType->getElement(k); + elt.Type->vw_destroy(elt.findIn(destLocation)); + } + return DynamicCastResult::Failure; + } + } + // We succeeded by casting each item. + return DynamicCastResult::SuccessViaCopy; + } + +} + +/******************************************************************************/ +/**************************** Function Destination ****************************/ +/******************************************************************************/ + +// The only thing that can be legally cast to a function is another function. + +static DynamicCastResult +tryCastToFunction( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Function); + const auto destFuncType = cast(destType); + + // Function casts succeed on exact matches, or if the target type is + // throwier than the source type. + // + // TODO: We could also allow ABI-compatible variance, such as casting + // a dynamic Base -> Derived to Derived -> Base. We wouldn't be able to + // perform a dynamic cast that required any ABI adjustment without a JIT + // though. + + if (srcType->getKind() != MetadataKind::Function) { + return DynamicCastResult::Failure; + } + auto srcFuncType = cast(srcType); + + // Check that argument counts and convention match (but ignore + // "throws" for now). + if (srcFuncType->Flags.withThrows(false) + != destFuncType->Flags.withThrows(false)) { + return DynamicCastResult::Failure; + } + + // If the target type can't throw, neither can the source. + if (srcFuncType->isThrowing() && !destFuncType->isThrowing()) + return DynamicCastResult::Failure; + + // The result and argument types must match. + if (srcFuncType->ResultType != destFuncType->ResultType) + return DynamicCastResult::Failure; + if (srcFuncType->getNumParameters() != destFuncType->getNumParameters()) + return DynamicCastResult::Failure; + if (srcFuncType->hasParameterFlags() != destFuncType->hasParameterFlags()) + return DynamicCastResult::Failure; + for (unsigned i = 0, e = srcFuncType->getNumParameters(); i < e; ++i) { + if (srcFuncType->getParameter(i) != destFuncType->getParameter(i) || + srcFuncType->getParameterFlags(i) != destFuncType->getParameterFlags(i)) + return DynamicCastResult::Failure; + } + + // Everything matches, so we can take/copy the function reference. + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } +} + +/******************************************************************************/ +/************************** Existential Destination ***************************/ +/******************************************************************************/ + +/// Check whether a type conforms to the given protocols, filling in a +/// list of conformances. +static bool _conformsToProtocols(const OpaqueValue *value, + const Metadata *type, + const ExistentialTypeMetadata *existentialType, + const WitnessTable **conformances) { + if (auto *superclass = existentialType->getSuperclassConstraint()) { + if (!swift_dynamicCastMetatype(type, superclass)) + return false; + } + + if (existentialType->isClassBounded()) { + if (!Metadata::isAnyKindOfClass(type->getKind())) + return false; + } + + for (auto protocol : existentialType->getProtocols()) { + if (!swift::_conformsToProtocol(value, type, protocol, conformances)) + return false; + if (conformances != nullptr && protocol.needsWitnessTable()) { + assert(*conformances != nullptr); + ++conformances; + } + } + + return true; +} + +// Cast to unconstrained `Any` +static DynamicCastResult +tryCastToUnconstrainedOpaqueExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + assert(cast(destType)->getRepresentation() + == ExistentialTypeRepresentation::Opaque); + auto destExistential + = reinterpret_cast(destLocation); + + // Fill in the type and value. + destExistential->Type = srcType; + auto *destBox = srcType->allocateBoxForExistentialIn(&destExistential->Buffer); + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destBox, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destBox, srcValue); + return DynamicCastResult::SuccessViaCopy; + } +} + +// Cast to constrained `Any` +static DynamicCastResult +tryCastToConstrainedOpaqueExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Opaque); + auto destExistential + = reinterpret_cast(destLocation); + + // Check for protocol conformances and fill in the witness tables. + // TODO (rdar://17033499) If the source is an existential, we should + // be able to compare the protocol constraints more efficiently than this. + if (_conformsToProtocols(srcValue, srcType, destExistentialType, + destExistential->getWitnessTables())) { + return tryCastToUnconstrainedOpaqueExistential( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } else { + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToClassExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Class); + auto destExistentialLocation + = reinterpret_cast(destLocation); + + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + + case MetadataKind::Metatype: { +#if SWIFT_OBJC_INTEROP + // Get an object reference to the metatype and try fitting that into + // the existential... + auto metatypePtr = reinterpret_cast(srcValue); + auto metatype = *metatypePtr; + if (auto tmp = swift_dynamicCastMetatypeToObjectConditional(metatype)) { + auto value = reinterpret_cast(&tmp); + auto type = reinterpret_cast(tmp); + if (_conformsToProtocols(value, type, destExistentialType, + destExistentialLocation->getWitnessTables())) { + auto object = *(reinterpret_cast(value)); + destExistentialLocation->Value = object; + if (takeOnSuccess) { + // We copied the pointer without retain, so the source is no + // longer valid... + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(object); + return DynamicCastResult::SuccessViaCopy; + } + } else { + // We didn't assign to destination, so the source reference + // is still valid and the reference count is still correct. + } + } +#endif + return DynamicCastResult::Failure; + } + + case MetadataKind::ObjCClassWrapper: + case MetadataKind::Class: + case MetadataKind::ForeignClass: { + auto object = getNonNullSrcObject(srcValue, srcType, destType); + if (_conformsToProtocols(srcValue, srcType, + destExistentialType, + destExistentialLocation->getWitnessTables())) { + destExistentialLocation->Value = object; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(object); + return DynamicCastResult::SuccessViaCopy; + } + } + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } + + return DynamicCastResult::Failure; +} + +// SwiftValue boxing is a failsafe that we only want to invoke +// after other approaches have failed. This is why it's not +// integrated into tryCastToClassExistential() above. +static DynamicCastResult +tryCastToClassExistentialViaSwiftValue( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Class); + auto destExistentialLocation + = reinterpret_cast(destLocation); + + // Fail if the target has constraints that make it unsuitable for + // a __SwiftValue box. + // FIXME: We should not have different checks here for + // Obj-C vs non-Obj-C. The _SwiftValue boxes should conform + // to the exact same protocols on both platforms. + bool destIsConstrained = destExistentialType->NumProtocols != 0; + if (destIsConstrained) { +#if SWIFT_OBJC_INTEROP // __SwiftValue is an Obj-C class + if (!findSwiftValueConformances( + destExistentialType, destExistentialLocation->getWitnessTables())) { + return DynamicCastResult::Failure; + } +#else // __SwiftValue is a native class + if (!swift_swiftValueConformsTo(destType, destType)) { + return DynamicCastResult::Failure; + } +#endif + } + +#if SWIFT_OBJC_INTEROP + auto object = bridgeAnythingToSwiftValueObject( + srcValue, srcType, takeOnSuccess); + destExistentialLocation->Value = object; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + return DynamicCastResult::SuccessViaCopy; + } +# else + // Note: Code below works correctly on both Obj-C and non-Obj-C platforms, + // but the code above is slightly faster on Obj-C platforms. + auto object = _bridgeAnythingToObjectiveC(srcValue, srcType); + destExistentialLocation->Value = object; + return DynamicCastResult::SuccessViaCopy; +#endif +} + +static DynamicCastResult +tryCastToErrorExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Error); + auto destBoxAddr = reinterpret_cast(destLocation); + + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::ForeignClass: // CF object => Error + case MetadataKind::ObjCClassWrapper: // Obj-C object => Error + case MetadataKind::Struct: // Struct => Error + case MetadataKind::Enum: // Enum => Error + case MetadataKind::Class: { // Class => Error + assert(destExistentialType->NumProtocols == 1); + const WitnessTable *errorWitness; + if (_conformsToProtocols( + srcValue, srcType, destExistentialType, &errorWitness)) { +#if SWIFT_OBJC_INTEROP + // If it already holds an NSError, just use that. + if (auto embedded = getErrorEmbeddedNSErrorIndirect( + srcValue, srcType, errorWitness)) { + *destBoxAddr = reinterpret_cast(embedded); + return DynamicCastResult::SuccessViaCopy; + } +#endif + + BoxPair destBox = swift_allocError( + srcType, errorWitness, srcValue, takeOnSuccess); + *destBoxAddr = reinterpret_cast(destBox.object); + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + return DynamicCastResult::SuccessViaCopy; + } + } + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastUnwrappingExistentialSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + auto srcExistentialType = cast(srcType); + + // Unpack the existential content + const Metadata *srcInnerType; + OpaqueValue *srcInnerValue; + switch (srcExistentialType->getRepresentation()) { + case ExistentialTypeRepresentation::Class: { + auto classContainer + = reinterpret_cast(srcValue); + srcInnerType = swift_getObjectType((HeapObject *)classContainer->Value); + srcInnerValue = reinterpret_cast(&classContainer->Value); + break; + } + case ExistentialTypeRepresentation::Opaque: { + auto opaqueContainer + = reinterpret_cast(srcValue); + srcInnerType = opaqueContainer->Type; + srcInnerValue = srcExistentialType->projectValue(srcValue); + break; + } + case ExistentialTypeRepresentation::Error: { + const SwiftError *errorBox + = *reinterpret_cast(srcValue); + auto srcErrorValue + = errorBox->isPureNSError() ? srcValue : errorBox->getValue(); + srcInnerType = errorBox->getType(); + srcInnerValue = const_cast(srcErrorValue); + break; + } + } + + srcFailureType = srcInnerType; + return tryCast(destLocation, destType, + srcInnerValue, srcInnerType, + destFailureType, srcFailureType, + takeOnSuccess & (srcInnerValue == srcValue), + mayDeferChecks); +} + +/******************************************************************************/ +/**************************** Opaque Destination ******************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToOpaque( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Opaque); + + // There's nothing special we can do here, but we have to have this + // empty function in order for the general casting logic to run + // for these types. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/**************************** Metatype Destination ****************************/ +/******************************************************************************/ + +#if SWIFT_OBJC_INTEROP +/// Check whether an unknown class instance is actually a type/metatype object. +static const Metadata *_getUnknownClassAsMetatype(void *object) { + // Objective-C class metadata are objects, so an AnyObject (or + // NSObject) may refer to a class object. + + // Test whether the object's isa is a metaclass, which indicates that + // the object is a class. + + Class isa = object_getClass((id)object); + if (class_isMetaClass(isa)) { + return swift_getObjCClassMetadata((const ClassMetadata *)object); + } + + return nullptr; +} +#endif + +static DynamicCastResult +tryCastToMetatype( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Metatype); + + const MetatypeMetadata *destMetatypeType = cast(destType); + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::Metatype: + case MetadataKind::ExistentialMetatype: { + const Metadata *srcMetatype = *(const Metadata * const *) srcValue; + if (auto result = swift_dynamicCastMetatype( + srcMetatype, destMetatypeType->InstanceType)) { + *((const Metadata **) destLocation) = result; + return DynamicCastResult::SuccessViaCopy; + } + return DynamicCastResult::Failure; + } + + case MetadataKind::Class: + case MetadataKind::ObjCClassWrapper: { +#if SWIFT_OBJC_INTEROP + // Some classes are actually metatypes + void *object = getNonNullSrcObject(srcValue, srcType, destType); + if (auto metatype = _getUnknownClassAsMetatype(object)) { + auto srcInnerValue = reinterpret_cast(&metatype); + auto srcInnerType = swift_getMetatypeMetadata(metatype); + return tryCast(destLocation, destType, srcInnerValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } +#endif + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +/// Perform a dynamic cast of a metatype to an existential metatype type. +static DynamicCastResult +_dynamicCastMetatypeToExistentialMetatype( + OpaqueValue *destLocation, const ExistentialMetatypeMetadata *destType, + const Metadata *srcMetatype, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + // The instance type of an existential metatype must be either an + // existential or an existential metatype. + auto destMetatype + = reinterpret_cast(destLocation); + + // If it's an existential, we need to check for conformances. + auto targetInstanceType = destType->InstanceType; + if (auto targetInstanceTypeAsExistential = + dyn_cast(targetInstanceType)) { + // Check for conformance to all the protocols. + // TODO: collect the witness tables. + const WitnessTable **conformance + = destMetatype ? destMetatype->getWitnessTables() : nullptr; + if (!_conformsToProtocols(nullptr, srcMetatype, + targetInstanceTypeAsExistential, + conformance)) { + return DynamicCastResult::Failure; + } + + if (destMetatype) + destMetatype->Value = srcMetatype; + return DynamicCastResult::SuccessViaCopy; + } + + // Otherwise, we're casting to SomeProtocol.Type.Type. + auto targetInstanceTypeAsMetatype = + cast(targetInstanceType); + + // If the source type isn't a metatype, the cast fails. + auto srcMetatypeMetatype = dyn_cast(srcMetatype); + if (!srcMetatypeMetatype) { + return DynamicCastResult::Failure; + } + + // The representation of an existential metatype remains consistent + // arbitrarily deep: a metatype, followed by some protocols. The + // protocols are the same at every level, so we can just set the + // metatype correctly and then recurse, letting the recursive call + // fill in the conformance information correctly. + + // Proactively set the destination metatype so that we can tail-recur, + // unless we've already done so. There's no harm in doing this even if + // the cast fails. + if (destLocation) + *((const Metadata **) destLocation) = srcMetatype; + + // Recurse. + auto srcInstanceType = srcMetatypeMetatype->InstanceType; + return _dynamicCastMetatypeToExistentialMetatype( + nullptr, + targetInstanceTypeAsMetatype, + srcInstanceType, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); +} + +// "ExistentialMetatype" is the metatype for an existential type. +static DynamicCastResult +tryCastToExistentialMetatype( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ExistentialMetatype); + + auto destExistentialMetatypeType + = cast(destType); + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::Metatype: // Metatype => ExistentialMetatype + case MetadataKind::ExistentialMetatype: { // ExistentialMetatype => ExistentialMetatype + const Metadata *srcMetatype = *(const Metadata * const *) srcValue; + return _dynamicCastMetatypeToExistentialMetatype( + destLocation, + destExistentialMetatypeType, + srcMetatype, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); + } + + case MetadataKind::ObjCClassWrapper: { + // Some Obj-C classes are actually metatypes +#if SWIFT_OBJC_INTEROP + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (auto metatype = _getUnknownClassAsMetatype(srcObject)) { + return _dynamicCastMetatypeToExistentialMetatype( + destLocation, + destExistentialMetatypeType, + metatype, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); + } +#endif + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +/******************************************************************************/ +/********************************** Dispatch **********************************/ +/******************************************************************************/ + +// A layer of functions that evaluate the source and/or destination types +// in order to invoke a tailored casting operation above. +// +// This layer also deals with general issues of unwrapping box types +// and invoking bridging conversions defined via the _ObjectiveCBridgeable +// protocol. +// +// Most of the caster functions above should be fairly simple: +// * They should deal with a single target type, +// * They should assume the source is fully unwrapped, +// * They should not try to report or cleanup failure, +// * If they can take, they should report the source was destroyed. + +// Based on the destination type alone, select a targeted casting function. +// This design avoids some redundant inspection of the destination type +// data, for example, when we unwrap source boxes. +static tryCastFunctionType *selectCasterForDest(const Metadata *destType) { + auto destKind = destType->getKind(); + switch (destKind) { + case MetadataKind::Class: + return tryCastToSwiftClass; + case MetadataKind::Struct: { + const auto targetDescriptor = cast(destType)->Description; + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(SS)) { + return tryCastToString; + } + if (targetDescriptor == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)) { + return tryCastToAnyHashable; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(Sa)) { + return tryCastToArray; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(SD)) { + return tryCastToDictionary; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(Sh)) { + return tryCastToSet; + } + return tryCastToStruct; + } + case MetadataKind::Enum: + return tryCastToEnum; + case MetadataKind::Optional: + return tryCastToOptional; + case MetadataKind::ForeignClass: + return tryCastToForeignClass; + case MetadataKind::Opaque: + return tryCastToOpaque; + case MetadataKind::Tuple: + return tryCastToTuple; + case MetadataKind::Function: + return tryCastToFunction; + case MetadataKind::Existential: { + auto existentialType = cast(destType); + switch (existentialType->getRepresentation()) { + case ExistentialTypeRepresentation::Opaque: + if (existentialType->NumProtocols == 0) { + return tryCastToUnconstrainedOpaqueExistential; // => Unconstrained Any + } else { + return tryCastToConstrainedOpaqueExistential; // => Non-class-constrained protocol + } + case ExistentialTypeRepresentation::Class: + return tryCastToClassExistential; // => AnyObject, with or without protocol constraints + case ExistentialTypeRepresentation::Error: // => Error existential + return tryCastToErrorExistential; + } + swift_runtime_unreachable( + "Unknown existential type representation in dynamic cast dispatch"); + } + case MetadataKind::Metatype: + return tryCastToMetatype; + case MetadataKind::ObjCClassWrapper: + return tryCastToObjectiveCClass; + case MetadataKind::ExistentialMetatype: + return tryCastToExistentialMetatype; + case MetadataKind::HeapLocalVariable: + case MetadataKind::HeapGenericLocalVariable: + case MetadataKind::ErrorObject: + // These are internal details of runtime-only structures, + // so will never appear in compiler-generated types. + // As such, they don't need support here. + swift_runtime_unreachable( + "Unexpected MetadataKind in dynamic cast dispatch"); + return nullptr; + default: + // If you see this message, then there is a new MetadataKind that I didn't + // know about when I wrote this code. Please figure out what it is, how to + // handle it, and add a case for it. + swift_runtime_unreachable( + "Unknown MetadataKind in dynamic cast dispatch"); + } +} + +// This top-level driver provides the general flow for all casting +// operations. It recursively unwraps source and destination as it +// searches for a suitable conversion. +static DynamicCastResult +tryCast( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + destFailureType = destType; + srcFailureType = srcType; + + //////////////////////////////////////////////////////////////////////// + // + // 1. If types match exactly, we can just move/copy the data. + // (The tryCastToXyz functions never see this trivial case.) + // + if (srcType == destType) { + if (takeOnSuccess) { + destType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + destType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } + } + + auto destKind = destType->getKind(); + auto srcKind = srcType->getKind(); + + //////////////////////////////////////////////////////////////////////// + // + // 2. Try directly casting the current srcValue to the target type. + // (If the dynamic type is different, try that too.) + // + auto tryCastToDestType = selectCasterForDest(destType); + if (tryCastToDestType == nullptr) { + return DynamicCastResult::Failure; + } + auto castResult = tryCastToDestType(destLocation, destType, srcValue, + srcType, destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(castResult)) { + return castResult; + } + if (srcKind == MetadataKind::Class + || srcKind == MetadataKind::ObjCClassWrapper + || srcKind == MetadataKind::ForeignClass) { + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + auto srcDynamicType = swift_getObjectType(srcObject); + if (srcDynamicType != srcType) { + srcFailureType = srcDynamicType; + auto castResult = tryCastToDestType( + destLocation, destType, srcValue, srcDynamicType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(castResult)) { + return castResult; + } + } + } + + //////////////////////////////////////////////////////////////////////// + // + // 3. Try recursively unwrapping _source_ boxes, including + // existentials, AnyHashable, SwiftValue, and Error. + // + switch (srcKind) { + + case MetadataKind::Class: { +#if !SWIFT_OBJC_INTEROP + // Try unwrapping native __SwiftValue implementation + if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, destType)) { + return DynamicCastResult::SuccessViaCopy; + } +#endif + break; + } + + case MetadataKind::ObjCClassWrapper: { +#if SWIFT_OBJC_INTEROP + // Try unwrapping Obj-C __SwiftValue implementation + auto subcastResult = tryCastUnwrappingObjCSwiftValueSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } +#endif + +#if SWIFT_OBJC_INTEROP + // Try unwrapping Obj-C NSError container + auto innerFlags = DynamicCastFlags::Default; + if (tryDynamicCastNSErrorToValue( + destLocation, srcValue, srcType, destType, innerFlags)) { + return DynamicCastResult::SuccessViaCopy; + } +#endif + break; + } + + case MetadataKind::Struct: { + auto srcStructType = cast(srcType); + auto srcStructDescription = srcStructType->getDescription(); + + // Try unwrapping AnyHashable container + if (srcStructDescription == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)) { + if (_swift_anyHashableDownCastConditionalIndirect( + srcValue, destLocation, destType)) { + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + + case MetadataKind::Existential: { + auto subcastResult = tryCastUnwrappingExistentialSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + break; + } + + default: + break; + } + + //////////////////////////////////////////////////////////////////////// + // + // 4. Try recursively unwrapping Optionals. First try jointly unwrapping + // both source and destination, then just destination, then just source. + // Note that if both are optional, we try all three of these! + // For example, consider casting an Optional to + // Optional. If T conforms, we need to + // unwrap both. But if it doesn't, we unwrap just the destination + // in order to cast Optional to the protocol directly. + // + if (destKind == MetadataKind::Optional) { + if (srcKind == MetadataKind::Optional) { + auto subcastResult = tryCastUnwrappingOptionalBoth( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + auto subcastResult = tryCastUnwrappingOptionalDestination( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + if (srcKind == MetadataKind::Optional) { + auto subcastResult = tryCastUnwrappingOptionalSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + //////////////////////////////////////////////////////////////////////// + // + // 5. Finally, explore bridging conversions via ObjectiveCBridgeable, + // Error, and __SwiftValue boxing. + // + switch (destKind) { + + case MetadataKind::Optional: { + // Optional supports _ObjectiveCBridgeable from an unconstrained AnyObject + if (srcType->getKind() == MetadataKind::Existential) { + auto srcExistentialType = cast(srcType); + if ((srcExistentialType->getRepresentation() == ExistentialTypeRepresentation::Class) + && (srcExistentialType->NumProtocols == 0) + && (srcExistentialType->getSuperclassConstraint() == nullptr) + && (srcExistentialType->isClassBounded())) { + auto toObjCResult = tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, false); + if (isSuccess(toObjCResult)) { + return toObjCResult; + } + } + } + + break; + } + + case MetadataKind::Existential: { + // Try general machinery for stuffing values into AnyObject: + auto destExistentialType = cast(destType); + if (destExistentialType->getRepresentation() == ExistentialTypeRepresentation::Class) { + // Some types have custom Objective-C bridging support... + auto subcastResult = tryCastFromObjCBridgeableToClass( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + + // Other types can be boxed into a __SwiftValue container... + auto swiftValueCastResult = tryCastToClassExistentialViaSwiftValue( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(swiftValueCastResult)) { + return swiftValueCastResult; + } + } + break; + } + + case MetadataKind::Class: + case MetadataKind::ObjCClassWrapper: + case MetadataKind::ForeignClass: { + // Try _ObjectiveCBridgeable to bridge _to_ a class type _from_ a + // struct/enum type. Note: Despite the name, this is used for both + // Swift-Swift and Swift-ObjC bridging + if (srcKind == MetadataKind::Struct || srcKind == MetadataKind::Enum) { + auto subcastResult = tryCastFromObjCBridgeableToClass( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + +#if SWIFT_OBJC_INTEROP + if (destKind == MetadataKind::ObjCClassWrapper) { + // If the destination type is an NSError or NSObject, and the source type + // is an Error, then the cast might succeed by NSError bridging. + if (auto srcErrorWitness = findErrorWitness(srcType)) { + if (destType == getNSErrorMetadata() + || destType == getNSObjectMetadata()) { + auto flags = DynamicCastFlags::Default; + auto error = dynamicCastValueToNSError(srcValue, srcType, + srcErrorWitness, flags); + *reinterpret_cast(destLocation) = error; + return DynamicCastResult::SuccessViaCopy; + } + } + } +#endif + + break; + } + + case MetadataKind::Struct: + case MetadataKind::Enum: { + // Use _ObjectiveCBridgeable to bridge _from_ a class type _to_ a + // struct/enum type. Note: Despite the name, this is used for both + // Swift-Swift and ObjC-Swift bridging + if (srcKind == MetadataKind::Class + || srcKind == MetadataKind::ObjCClassWrapper + || srcKind == MetadataKind::ForeignClass) { + auto subcastResult = tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + // Note: In theory, if src and dest are both struct/enum types, we could see + // if the ObjC bridgeable class types matched and then do a two-step + // conversion from src -> bridge class -> dest. Such ambitious conversions + // might cause more harm than good, though. In particular, it could + // undermine code that uses a series of `as?` to quickly determine how to + // handle a particular object. + break; + } + + default: + break; + } + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/****************************** Main Entrypoint *******************************/ +/******************************************************************************/ + +// XXX REMOVE ME XXX TODO XXX +// Declare the old entrypoint +SWIFT_RUNTIME_EXPORT +bool +swift_dynamicCast_OLD(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags); +// XXX REMOVE ME XXX TODO XXX + +/// ABI: Perform a dynamic cast to an arbitrary type. +static bool +swift_dynamicCastImpl(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags) +{ + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // Support switching to the old implementation while the new one + // is still settling. Once the new implementation is stable, + // I'll rip the old one entirely out. + static bool useOldImplementation = false; // Default: NEW Implementation + static swift_once_t Predicate; + swift_once( + &Predicate, + [](void *) { + // Define SWIFT_OLD_DYNAMIC_CAST_RUNTIME=1 to use the old runtime + // dynamic cast logic. + auto useOld = getenv("SWIFT_OLD_DYNAMIC_CAST_RUNTIME"); + if (useOld) { + useOldImplementation = true; + } + }, nullptr); + if (useOldImplementation) { + return swift_dynamicCast_OLD(destLocation, srcValue, + srcType, destType, flags); + } + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + + // If the compiler has asked for a "take", we can + // move pointers without ref-counting overhead. + bool takeOnSuccess = flags & DynamicCastFlags::TakeOnSuccess; + // Unconditional casts are allowed to crash the program on failure. + // We can exploit that for performance: return a partial conversion + // immediately and do additional checks lazily when the results are + // actually accessed. + bool mayDeferChecks = flags & DynamicCastFlags::Unconditional; + + // Attempt the cast... + const Metadata *destFailureType = destType; + const Metadata *srcFailureType = srcType; + auto result = tryCast( + destLocation, destType, + srcValue, srcType, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks); + + switch (result) { + case DynamicCastResult::Failure: + if (flags & DynamicCastFlags::Unconditional) { + swift_dynamicCastFailure(srcFailureType, destFailureType); + } + if (flags & DynamicCastFlags::DestroyOnFailure) { + srcType->vw_destroy(srcValue); + } + return false; + case DynamicCastResult::SuccessViaCopy: + if (takeOnSuccess) { // We copied, but compiler asked for take. + srcType->vw_destroy(srcValue); + } + return true; + case DynamicCastResult::SuccessViaTake: + return true; + } +} + +#define OVERRIDE_DYNAMICCASTING COMPATIBILITY_OVERRIDE +#include "CompatibilityOverride.def" diff --git a/test/stdlib/CastTraps.swift.gyb b/test/Casting/CastTraps.swift.gyb similarity index 61% rename from test/stdlib/CastTraps.swift.gyb rename to test/Casting/CastTraps.swift.gyb index e5608874d028d..95c7cbbebfe31 100644 --- a/test/stdlib/CastTraps.swift.gyb +++ b/test/Casting/CastTraps.swift.gyb @@ -5,17 +5,17 @@ // FIXME: Casting.cpp has dozens of places to fail a cast. This test does not // attempt to enumerate them all. -// REQUIRES: objc_interop - import StdlibUnittest - +#if _runtime(_ObjC) import Foundation +#endif % types = [] % objectTypes = [] % protocolTypes = [] +% ObjCTypes = [] % types.append(['main.Class1', 'main.Class2']) % objectTypes.append(['main.Class1', 'main.Class2']) @@ -28,11 +28,15 @@ struct Struct2 { } % types.append(['main.ObjCClass1', 'main.ObjCClass2']) % objectTypes.append(['main.ObjCClass1', 'main.ObjCClass2']) +% ObjCTypes.extend(['main.ObjCClass1', 'main.ObjCClass2']) +#if _runtime(_ObjC) class ObjCClass1 : NSObject { } class ObjCClass2 : NSObject { } +#endif % types.append(['DateFormatter', 'NumberFormatter']) % objectTypes.append(['DateFormatter', 'NumberFormatter']) +% ObjCTypes.extend(['DateFormatter', 'NumberFormatter']) // non-Swift Objective-C class % protocolTypes.append('main.Proto1') @@ -40,6 +44,7 @@ class ObjCClass2 : NSObject { } protocol Proto1 { } protocol Proto2 { } % protocolTypes.append('URLSessionDelegate') +% ObjCTypes.append('URLSessionDelegate') // non-Swift Objective-C protocol @@ -51,6 +56,7 @@ var CastTrapsTestSuite = TestSuite("CastTraps") % for (t1, _) in types: % for (_, t2) in types: +% if t1 not in ObjCTypes and t2 not in ObjCTypes: CastTrapsTestSuite.test("${t1}__${t2}") .skip(.custom( { _isFastAssertConfiguration() }, @@ -67,6 +73,7 @@ CastTrapsTestSuite.test("${t1}__${t2}") _blackHole(r) } +% end % end % end @@ -76,6 +83,7 @@ CastTrapsTestSuite.test("${t1}__${t2}") % for (t1, _) in objectTypes: % for (t2) in protocolTypes: +% if t1 not in ObjCTypes and t2 not in ObjCTypes: CastTrapsTestSuite.test("${t1}__${t2}") .skip(.custom( { _isFastAssertConfiguration() }, @@ -92,7 +100,47 @@ CastTrapsTestSuite.test("${t1}__${t2}") _blackHole(r) } +% end % end % end +protocol P2 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastTrapsTestSuite.test("Unexpected null") + .crashOutputMatches("Found unexpected null pointer value while trying to cast value of type '") + .crashOutputMatches("Foo'") + .crashOutputMatches(" to '") + .crashOutputMatches("P2'") + .code +{ + class Foo {} + let n = UnsafeRawPointer(bitPattern: 0) + var o: Foo = unsafeBitCast(n, to: Foo.self) + let r = o as Any + expectCrashLater() + let s = r as? P2 + _blackHole(s) +} +} + + +#if _runtime(_ObjC) +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastTrapsTestSuite.test("Unexpected Obj-C null") + .crashOutputMatches("Found unexpected null pointer value while trying to cast value of type '") + .crashOutputMatches("NSObject'") + .crashOutputMatches(" to '") + .crashOutputMatches("P2'") + .code +{ + let n = UnsafeRawPointer(bitPattern: 0) + var o: NSObject = unsafeBitCast(n, to: NSObject.self) + let r = o as Any + expectCrashLater() + let s = r as? P2 + _blackHole(s) +} +} +#endif + runAllTests() diff --git a/test/Casting/Casts.swift b/test/Casting/Casts.swift new file mode 100644 index 0000000000000..54eeef85adff6 --- /dev/null +++ b/test/Casting/Casts.swift @@ -0,0 +1,763 @@ +// Casts.swift - Tests for conversion between types. +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +// ----------------------------------------------------------------------------- +/// +/// Contains tests for non-trapping type conversions reported by users. +/// +// ----------------------------------------------------------------------------- +// RUN: %empty-directory(%t) +// +// RUN: %target-build-swift -swift-version 5 -g -Onone -Xfrontend -enable-experimental-concurrency -module-name a %s -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %target-run %t/a.swift5.Onone.out +// +// RUN: %target-build-swift -swift-version 5 -g -O -Xfrontend -enable-experimental-concurrency -module-name a %s -o %t/a.swift5.O.out +// RUN: %target-codesign %t/a.swift5.O.out +// RUN: %target-run %t/a.swift5.O.out +// +// REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib + +import StdlibUnittest +#if _runtime(_ObjC) +import Foundation +#endif + +func blackhole(_ t: T) { } + +private func runtimeCast(_ from: T, to: U.Type) -> U? { + return from as? U +} + +let CastsTests = TestSuite("Casts") + +// Test for SR-426: missing release for some types after failed conversion +CastsTests.test("No leak for failed tuple casts") { + let t: Any = (1, LifetimeTracked(0)) + expectFalse(t is Any.Type) +} + +protocol P {} +class ErrClass : Error { } + +CastsTests.test("No overrelease of existential boxes in failed casts") { + // Test for crash from SR-392 + // We fail casts of an existential box repeatedly + // to ensure it does not get over-released. + func bar(_ t: T) { + for _ in 0..<10 { + if case let a as P = t { + _ = a + } + } + } + + let err: Error = ErrClass() + bar(err) +} + +extension Int : P {} + +// Test for SR-7664: Inconsistent optional casting behaviour with generics +// Runtime failed to unwrap multiple levels of Optional when casting. +CastsTests.test("Multi-level optionals can be casted") { + func testSuccess(_ x: From, from: From.Type, to: To.Type) { + expectNotNil(x as? To) + } + func testFailure(_ x: From, from: From.Type, to: To.Type) { + expectNil(x as? To) + } + testSuccess(42, from: Int?.self, to: Int.self) + testSuccess(42, from: Int??.self, to: Int.self) + testSuccess(42, from: Int???.self, to: Int.self) + testSuccess(42, from: Int???.self, to: Int?.self) + testSuccess(42, from: Int???.self, to: Int??.self) + testSuccess(42, from: Int???.self, to: Int???.self) + testFailure(42, from: Int?.self, to: String.self) + testFailure(42, from: Int??.self, to: String.self) + testFailure(42, from: Int???.self, to: String.self) +} + +// Test for SR-9837: Optional.none not casting to Optional.none in generic context +CastsTests.test("Optional.none can be casted to Optional.none in generic context") { + func test(_ type: T.Type) -> T? { + return Any?.none as? T + } + + expectEqual(type(of: test(Bool.self)), Bool?.self) + expectEqual(type(of: test(Bool?.self)), Bool??.self) +} + +// Test for SR-3871: Cannot cast from ObjC existential without going through AnyObject +#if _runtime(_ObjC) +protocol P2 {} +CastsTests.test("Cast from ObjC existential to Protocol (SR-3871)") { + if #available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { + struct S: P2 {} + + class ObjCWrapper { + @objc dynamic let any: Any = S() + init() {} + } + let a = ObjCWrapper().any + expectTrue(a is P2) + // In SR-3871, the following cast failed (everything else here succeeded) + expectNotNil(a as? P2) + expectNotNil(a as? S) + let b = a as AnyObject + expectTrue(a is P2) + expectNotNil(b as? P2) + expectNotNil(b as? S) + } +} +#endif + +protocol P3 {} +CastsTests.test("Cast from Swift existential to Protocol") { + struct S: P3 {} + class SwiftWrapper { + let any: Any = S() + init() {} + } + let a = SwiftWrapper().any + expectTrue(a is P3) + expectNotNil(a as? P3) + expectNotNil(a as? S) + let b = a as AnyObject + expectTrue(b is P3) + expectNotNil(b as? P3) + expectNotNil(b as? S) +} + + +#if _runtime(_ObjC) +extension CFBitVector : P { + static func makeImmutable(from values: Array) -> CFBitVector { + return CFBitVectorCreate(/*allocator:*/ nil, values, values.count * 8) + } +} + +extension CFMutableBitVector { + static func makeMutable(from values: Array) -> CFMutableBitVector { + return CFBitVectorCreateMutableCopy( + /*allocator:*/ nil, + /*capacity:*/ 0, + CFBitVector.makeImmutable(from: values)) + } +} + +func isP(_ t: T) -> Bool { + return t is P +} + +CastsTests.test("Dynamic casts of CF types to protocol existentials (SR-2289)") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "This test behaves unpredictably in optimized mode.")) +.code { + expectTrue(isP(10 as Int)) + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(isP(CFBitVector.makeImmutable(from: [10, 20]))) + expectTrue(isP(CFMutableBitVector.makeMutable(from: [10, 20]))) + } +} +#endif + +// Another test for SR-3871, SR-5590, SR-6309, SR-8651: +// user type in a _SwiftValue in an Optional can't be cast to a protocol. +// Note: This uses the (misnamed) _bridgeAnythingToObjectiveC so it can +// test these paths on Linux as well. +protocol P6309 {} +CastsTests.test("Casting struct -> Obj-C -> Protocol fails (SR-3871, SR-5590, SR-6309, SR-8651)") { + struct S: P6309 { + let value: Int + let tracker = LifetimeTracked(13) + } + + let a: P6309 = S(value: 13) + + let b = _bridgeAnythingToObjectiveC(a) + let d = b as? Any + let e = d as? P6309 + expectNotNil(e) +} + + +protocol P4552 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Casting Any(Optional(T)) -> Protocol fails (SR-4552)") { + struct S: P4552 { + let tracker = LifetimeTracked(13) + } + + let a = S() + let b: S? = a + let c = b as? Any + let d = c as? P4552 + expectNotNil(d) +} +} + +// rdar://27108240 (Optional casting bug (crash)) +protocol Key { + associatedtype Value +} +CastsTests.test("Cast to associated type") { + // Helper function to bypass compiler cast optimizations + func runtimeCast (_ x: From, to: To.Type) -> To? { + return x as? To + } + struct StringKey : Key { + typealias Value = String? + } + var string: String? + func value(forKey key: K.Type) { + let b = runtimeCast(string, to: K.Value.self) + expectNotNil(b) + let c = string as? K.Value + expectNotNil(c) + } + value(forKey: StringKey.self) +} + +#if _runtime(_ObjC) +// rdar://36288786 (Swift metatype stored in an Objective-C id property can't be typecast back to its original type) +CastsTests.test("Store Swift metatype in ObjC property and cast back to Any.Type") { + class MyObj { + var sVar: Any? = nil + @objc dynamic var objcVar: Any? = nil + } + + let a = MyObj() + + // Double values + a.sVar = 1.234 + a.objcVar = 1.234 + + let sValue1 = a.sVar as? Double + let objcValue1 = a.objcVar as? Double + expectEqual(sValue1, objcValue1) + + // Swift types + let b = Bool.self + a.sVar = b + a.objcVar = b + + let sValue2 = a.sVar as? Any.Type + let objcValue2 = a.objcVar as? Any.Type + expectTrue(sValue2 == b) + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(sValue2 == objcValue2) + expectTrue(objcValue2 == b) + } +} +#endif + +// rdar://37793004 ([dynamic casting] [SR-7049]: Enums don't cast back from AnyHashable) +CastsTests.test("Enums don't cast back from AnyHashable (SR-7049)") { + enum E { + case a + } + + // This works as expected. + let str: AnyHashable = "hello" + expectNotNil(str as? String) // Optional("hello") + expectNotNil(str as? String as Any) // Optional("hello") + + // This doesn't. + let ea: AnyHashable = E.a + expectNotNil(ea as? E) + expectNotNil(ea as? E as Any) + expectEqual((ea as? E), E.a) +} + +#if _runtime(_ObjC) +//rdar://39415812 ([dynamic casting] [SR-7432]: Can't see through boxed _SwiftValue when casting from @objc Type) +@objc(Exporter) +protocol Exporter: NSObjectProtocol { + var type: Any { get } + func export(item: Any) -> String? +} +CastsTests.test("Casts from @objc Type") { + struct User { var name: String } + + final class UserExporter: NSObject, Exporter { + var type: Any { return User.self } + func export(item: Any) -> String? { + let u = item as? User + return u?.name + } + } + + let user = User(name: "Kermit") + let exporter: Exporter = UserExporter() + + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(exporter.type is User.Type) + } + expectNotNil(exporter.export(item: user)) +} +#endif + +#if _runtime(_ObjC) +// rdar://44467533 (Swift master branch: conditional casts for _ObjectiveCBridgeable miscompile in swift-corelibs-foundation) +CastsTests.test("Conditional NSNumber -> Bool casts") { + let x = NSNumber(value: -1) as? Bool + expectNil(x) +} +#endif + +// rdar://45217461 ([dynamic casting] [SR-8964]: Type check operator (is) fails for Any! variable holding an Error (struct) value) +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Casts from Any(struct) to Error (SR-8964)") { + struct MyError: Error { } + + let a: Any! = MyError() + let b: Any = a + expectTrue(b is Error) +} +} + +#if _runtime(_ObjC) +// rdar://15494623 (Handle dynamic cast to archetype bound to ObjC existential) +CastsTests.test("Dynamic cast to ObjC protocol") { + func genericCast(x: NSObject, _: T.Type) -> T? { + return x as? T + } + + let n: NSNumber = 1 + let copying = genericCast(x: n, NSCopying.self) + expectNotNil(copying) +} +#endif + +// SR-6126 +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Nil handling for Optionals and Arrays (SR-6126)") { + func check(_ arg: Int??) -> String { + switch arg { + case .none: + return ".none" + case .some(.none): + return ".some(.none)" + case .some(.some): + return ".some(.some)" + } + } + + let x: Int? = .none + let y: [Int?] = [.none] + + let a = x as Int?? + let b = (x as? Int??)! + let b2 = runtimeCast(x, to: Int??.self)! + let c = Int?.none as Int?? + let d = (Int?.none as? Int??)! + let d2 = runtimeCast(Int?.none, to: Int??.self)! + let e = (y as [Int??]).first! + let f = (y as? [Int??])!.first! + let f2 = runtimeCast(y, to: [Int??].self)!.first! + let g = ([Int?.none] as [Int??]).first! + let h = ([Int?.none] as? [Int??])!.first! + let h2 = runtimeCast([Int?.none], to: [Int??].self)!.first! + + // Original reporter believes all of these should be .some(.none) + expectEqual(".some(.none)", check(a)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(b)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(b2)) + expectEqual(".some(.none)", check(c)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(d)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(d2)) + expectEqual(".some(.none)", check(e)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(f)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(f2)) + expectEqual(".some(.none)", check(g)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(h)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(h2)) +} +} + +protocol SwiftProtocol {} +CastsTests.test("Swift Protocol Metatypes don't self-conform") { + let a = SwiftProtocol.self + // `is P.Protocol` tests whether the argument is a subtype of P. + // In particular, the protocol identifier `P.self` is such a subtype. + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectNotNil(runtimeCast(a, to: SwiftProtocol.Protocol.self)) // Fixed by rdar://58991956 + } + expectNotNil(a as? SwiftProtocol.Protocol) + expectTrue(a is SwiftProtocol.Protocol) + blackhole(a as! SwiftProtocol.Protocol) // Should not trap + + // `is P.Type` tests conformance to P. Protocols cannot conform to + // protocols, so these always fail. + expectNil(runtimeCast(a, to: SwiftProtocol.Type.self)) + expectNil(a as? SwiftProtocol.Type) + expectFalse(a is SwiftProtocol.Type) +} + +CastsTests.test("Self-conformance for Any.self") { + let b = Any.self + expectNotNil(runtimeCast(b, to: Any.Protocol.self)) + blackhole(b as! Any.Protocol) // Should not trap + expectTrue(b is Any.Protocol) + expectNotNil(b as? Any.Protocol) + + // Unlike most other protocols, Any.self does conform to Any + expectNotNil(runtimeCast(b, to: Any.Type.self)) + expectNotNil(b as? Any.Type) + expectTrue(b is Any.Type) + blackhole(b as! Any.Type) +} + +// rdar://59067748 (Error Protocol should self-conform in optimized casts) +CastsTests.test("Self-conformance for Error.self") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "Cast optimizer breaks this test")) +.code { + let c = Error.self + expectNotNil(runtimeCast(c, to: Error.Protocol.self)) + expectNotNil(c as? Error.Protocol) + expectTrue(c is Error.Protocol) + blackhole(c as! Error.Protocol) + + // Unlike most other protocols, Error.self does conform to Error + expectNotNil(runtimeCast(c, to: Error.Type.self)) + expectFailure { expectNotNil(c as? Error.Type) } + expectFailure { expectTrue(c is Error.Type) } + // blackhole(c as! Error.Type) // Should not trap, but currently does +} + +// rdar://59067556 (Obj-C Protocol Metatypes should self-conform) +#if _runtime(_ObjC) +@objc protocol ObjCProtocol {} +CastsTests.test("ObjC Protocol Metatypes self-conform") { + let a = ObjCProtocol.self + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectNotNil(runtimeCast(a, to: ObjCProtocol.Protocol.self)) + } + expectNotNil(a as? ObjCProtocol.Protocol) + expectTrue(a is ObjCProtocol.Protocol) + blackhole(a as! ObjCProtocol.Protocol) + + // Unlike Swift protocols, ObjC protocols do conform to themselves + expectFailure { expectNotNil(runtimeCast(a, to: ObjCProtocol.Type.self)) } + expectFailure { expectNotNil(a as? ObjCProtocol.Type) } + expectFailure { expectTrue(a is ObjCProtocol.Type) } + // blackhole(a as! ObjCProtocol.Type) // Should not trap, but currently does +} +#endif + +#if _runtime(_ObjC) +protocol NewStringProtocol {} +extension String: NewStringProtocol { } +CastsTests.test("String/NSString extension compat") { + let x: Any = NSString() + expectFailure { expectNotNil(runtimeCast(x, to: NewStringProtocol.self)) } + expectFailure { expectNotNil(x as? NewStringProtocol) } +} +#endif + +protocol P1999 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Cast Any(Optional(class)) to Protocol type (SR-1999)") { + class Foo: P1999 { } + + let optionalFoo : Foo? = Foo() + let anyValue: Any = optionalFoo + + let foo1 = anyValue as? Foo + expectNotNil(foo1) + + let foo2 = anyValue as? P1999 + expectNotNil(foo2) + + let foo3 = runtimeCast(anyValue, to: Foo.self) + expectNotNil(foo3) + + let foo4 = runtimeCast(anyValue, to: P1999.self) + expectNotNil(foo4) +} +} + +#if _runtime(_ObjC) +CastsTests.test("Dict value casting (SR-2911)") { + var dict: [AnyHashable: String] = [:] + dict["Key"] = "Value" + expectNotNil(dict["Key"] as? NSString) + expectNotNil(runtimeCast(dict["Key"], to: NSString.self)) +} +#endif + +#if _runtime(_ObjC) +CastsTests.test("String coercions should work on Linux (SR-12020)") { + let a = "abc" as Substring as NSString + let b = "abc" as NSString + expectEqual(a, b) + + let c = "abc" as Substring + let d = c as? NSString + let e = "abc" as? NSString + expectEqual(d, e) + + let f = runtimeCast(d, to: NSString.self) + expectEqual(e, f) +} +#endif + +class ClassInt: Equatable, Hashable { + private var tracker = LifetimeTracked(77) + static func == (lhs: ClassInt, rhs: ClassInt) -> Bool {return true} + func hash(into hasher: inout Hasher) {} +} +CastsTests.test("AnyHashable(Class) -> Obj-C -> Class") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "Cast optimizer breaks this test")) +.code { + let a = ClassInt() + let b = runtimeCast(a, to: AnyHashable.self)! + let c = _bridgeAnythingToObjectiveC(b) + let d = /* SwiftValueBox(AnyHashable(ClassInt)) */ c as? ClassInt + expectNotNil(d) + let d2 = runtimeCast(c, to: ClassInt.self) + expectNotNil(d2) + let e = runtimeCast(/* SwiftValueBox(AnyHashable(ClassInt)) */ c, to: ClassInt.self) + expectNotNil(e) +} + +#if _runtime(_ObjC) +// rdar://58999120 +CastsTests.test("Error -> NSError -> Protocol transitivity (SR-12095)") { + enum NonConformingError: Error { + case ok + } + + let nonConformingError: Error = NonConformingError.ok + + // NSError conforms to CustomStringConvertible, so ... + let conformingError = nonConformingError as? NSError + expectTrue(conformingError is CustomStringConvertible) + expectNotNil(conformingError as? CustomStringConvertible) + + // Our error type does not conform directly, but should conform + // indirectly because of NSError... + // Note: Known broken in both runtime and compiler. + expectFailure { expectTrue(nonConformingError is CustomStringConvertible) } + expectFailure { expectNotNil(nonConformingError as? CustomStringConvertible) } +} +#endif + +#if _runtime(_ObjC) +CastsTests.test("Runtime crash casting Obj-C object to Obj-C protocol (rdar://16449805)") { + // FIXME: The reported crash was for `NSPoint(x:0, y:0) as? NSCoding`, + // but NSPoint seems to not be available on 32-bit platforms. + expectNotNil(NSString() as? NSCoding) +} +#endif + +CastsTests.test("Casting Swift Error-conforming types to Error existentials") { + enum Foo: Error { + case OK + case Broken + } + let a = Foo.Broken + let b = a as? Error + expectNotNil(b) + let c = b as? Foo + expectNotNil(c) + let d = Foo.self as? Error.Type + expectNotNil(d) +} + +#if _runtime(_ObjC) +CastsTests.test("Casting NSError <-> Error") { + @objc class Bar: NSError { + init() {super.init(domain: "Bar", code: 99)} + required init?(coder: NSCoder) {super.init(coder: coder)} + } + let e = Bar.self as? Error.Type + expectNotNil(e) + let f = Bar.self as? Bar.Type + expectNotNil(f) + let g = Bar() as? Error + expectNotNil(g) +} +#endif + +// Foundation's JSON handling makes heavy use of passing Any? inside of Any +// existentials. That inspired the following three checks: +CastsTests.test("[Any(Any?)] -> [Any?] should prefer unwrapping source") { + let a: Any? = nil + let b: [Any] = [a as Any] + let c = b as? [Any?] + let d = c! + let e = d[0] + expectNil(e) +} + +CastsTests.test("Any(Any?) -> Any? should prefer unwrapping source") { + let a: Any? = nil + let b: Any = a + let c = b as? Any? + let d = c! + expectNil(d) +} + +#if _runtime(_ObjC) +CastsTests.test("NSNull?.none -> Any? should set outer nil") { + let a: NSNull? = nil + let b = a as? Any? + let c = b! + expectNil(c) +} +#endif + +CastsTests.test("Int??.some(nil) => Int??? should inject naturally") { + let a: Int?? = .some(nil) + let b = a as? Int??? + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +CastsTests.test("Int??.some(nil) => String??? should inject naturally") { + let a: Int?? = .some(nil) + let b = runtimeCast(a, to: String???.self) + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +CastsTests.test("Int??.some(nil) => Any??? should inject naturally") { + let a: Int?? = .some(nil) + let b = a as? Any??? + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +#if _runtime(_ObjC) +CastsTests.test("NSString -> String fast path") { + let a = "short" as NSString + expectNotNil(a as? String) + let b = runtimeCast(a, to: String.self) + expectNotNil(b) + + let c = "Long (adj) -- extended, large, the opposite of short" as NSString + expectNotNil(c as? String) + let d = runtimeCast(c, to: String.self) + expectNotNil(d) + + let e = NSMutableString("not read-only") + expectNotNil(e as? String) + let f = runtimeCast(e, to: String.self) + expectNotNil(f) + + let g = CFStringCreateWithCString(nil, "hello, world", CFStringBuiltInEncodings.UTF8.rawValue) + expectNotNil(g as? String) + let h = runtimeCast(g, to: String.self) + expectNotNil(h) + + let i = CFStringCreateMutable(nil, 0) + expectNotNil(i as? String) + let j = runtimeCast(i, to: String.self) + expectNotNil(j) +} +#endif + +// This fails in optimized builds because after inlining `runtimeCast`, +// the resulting SIL cast operation is left in a form that IRGen can't +// correctly handle. +//CastsTests.test("Optimized metatype -> AnyObject cast") { +// struct StructInt { } +// let a = StructInt.self +// let b = runtimeCast(a, to: AnyObject.self) +// expectNotNil(b) +//} + +CastsTests.test("Any.Protocol") { + class C {} + struct S {} + func isAnyProtocol(_ type: T.Type) -> Bool { + let result = T.self is Any.Protocol + if result { + // `as!` should succeed if `is` does + blackhole(T.self as! Any.Protocol) + } + return result + } + func isAnyType(_ type: T.Type) -> Bool { + return T.self is Any.Type + } + func isType(_ type: T.Type, to: U.Type) -> Bool { + return T.self is U.Type + } + + expectTrue(Int.self is Any.Type) + expectNotNil(Int.self as? Any.Type) + expectTrue(isAnyType(Int.self)) + expectFalse(Int.self is Any.Protocol) + expectNil(Int.self as? Any.Protocol) + expectFalse(isAnyProtocol(Int.self)) + expectFalse(isType(Int.self, to: Any.self)) + + expectTrue(C.self is Any.Type) + expectNotNil(C.self as? Any.Type) + expectTrue(isAnyType(C.self)) + expectFalse(C.self is Any.Protocol) + expectNil(C.self as? Any.Protocol) + expectFalse(isAnyProtocol(C.self)) + expectFalse(isType(C.self, to: Any.self)) + + expectTrue(S.self is Any.Type) + expectNotNil(S.self as? Any.Type) + expectTrue(isAnyType(S.self)) + expectFalse(S.self is Any.Protocol) + expectNil(S.self as? Any.Protocol) + expectFalse(isAnyProtocol(S.self)) + expectFalse(isType(S.self, to: Any.self)) + + expectTrue(Any.self is Any.Type) + expectNotNil(Any.self as? Any.Type) + expectTrue(isAnyType(Any.self)) + expectTrue(Any.self is Any.Protocol) + expectNotNil(Any.self as? Any.Protocol) + expectTrue(isAnyProtocol(Any.self)) + expectTrue(isType(Any.self, to: Any.self)) + + expectTrue(Any?.self is Any.Type) + expectNotNil(Any?.self as? Any.Type) + expectTrue(isAnyType(Any?.self)) + expectFalse(Any?.self is Any.Protocol) + expectNil(Any?.self as? Any.Protocol) + expectFalse(isAnyProtocol(Any?.self)) + expectFalse(isType(Any?.self, to: Any.self)) +} + +CastsTests.test("Async function types") { + let asyncFnType: Any.Type = (() async -> Void).self + let fnType: Any.Type = (() -> Void).self + + expectTrue(fnType is (() -> Void).Type) + expectTrue(asyncFnType is (() async -> Void).Type) + expectFalse(fnType is (() async -> Void).Type) + expectFalse(asyncFnType is (() -> Void).Type) +} + +runAllTests() diff --git a/test/Interpreter/SDK/protocol_lookup_foreign.swift b/test/Interpreter/SDK/protocol_lookup_foreign.swift index e0836c4cfa31d..f0565dc042a65 100644 --- a/test/Interpreter/SDK/protocol_lookup_foreign.swift +++ b/test/Interpreter/SDK/protocol_lookup_foreign.swift @@ -1,4 +1,4 @@ -// RUN: %target-run-simple-swift | %FileCheck %s +// RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: objc_interop @@ -10,38 +10,62 @@ // XFAIL: swift_test_mode_optimize_unchecked import Foundation +import StdlibUnittest protocol Fooable { - func foo() + func foo() -> String } -func fooify(_ x: T) { +func fooify(_ x: T) -> String { if let foo = x as? Fooable { - foo.foo() + return foo.foo() } else { - print("not fooable") + return "not fooable" } } extension NSRect: Fooable { - func foo() { print("NSRect") } + func foo() -> String { return "NSRect" } } extension CFSet: Fooable { - func foo() { print("CFSet") } + func foo() -> String { return "CFSet" } } extension NSString: Fooable { - func foo() { print("NSString") } + func foo() -> String { return "NSString" } } -fooify(NSRect()) // CHECK: NSRect -fooify(NSPoint()) // CHECK-NEXT: not fooable -// FIXME: CF types get their ObjC class dynamically looked up during dynamic -// casting. -fooify(CFSetCreate(kCFAllocatorDefault, nil, 0, nil)!) // TODO-NEXT: CFSet CHECK-NEXT: not fooable -fooify(CFArrayCreate(kCFAllocatorDefault, nil, 0, nil)!) // CHECK-NEXT: not fooable -fooify(NSString()) // CHECK-NEXT: NSString -fooify(NSMutableString()) // CHECK-NEXT: NSString -fooify(NSSet()) // CHECK-NEXT: not fooable +var ProtocolLookupForeign = TestSuite("ProtocolLookupForeign") +ProtocolLookupForeign.test("NSRect") { + expectEqual("NSRect", fooify(NSRect())) +} + +ProtocolLookupForeign.test("NSPoint") { + expectEqual("not fooable", fooify(NSPoint())) +} + +ProtocolLookupForeign.test("CFSet") { + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectEqual("CFSet", fooify(CFSetCreate(kCFAllocatorDefault, nil, 0, nil)!)) + } +} + +ProtocolLookupForeign.test("CFArray") { + expectEqual("not fooable", fooify(CFArrayCreate(kCFAllocatorDefault, nil, 0, nil)!)) +} + +ProtocolLookupForeign.test("NSString") { + expectEqual("NSString", fooify(NSString())) +} + +ProtocolLookupForeign.test("NSMutableString") { + expectEqual("NSString", fooify(NSMutableString())) +} + +ProtocolLookupForeign.test("NSSet") { + expectEqual("not fooable", fooify(NSSet())) +} + +runAllTests() diff --git a/test/Interpreter/tuple_casts.swift b/test/Interpreter/tuple_casts.swift index 4c0dacafa57f9..0f662932ed6e7 100644 --- a/test/Interpreter/tuple_casts.swift +++ b/test/Interpreter/tuple_casts.swift @@ -1,7 +1,13 @@ // RUN: %target-run-simple-swift -// RUN: %target-build-swift -O %s -o %t/a.out.optimized -// RUN: %target-codesign %t/a.out.optimized -// RUN: %target-run %t/a.out.optimized +// +// RUN: %target-build-swift -swift-version 5 -O %s -o %t/a.swift5.O.out +// RUN: %target-codesign %t/a.swift5.O.out +// RUN: %target-run %t/a.swift5.O.out +// +// RUN: %target-build-swift -swift-version 5 -Onone %s -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %target-run %t/a.swift5.Onone.out +// // REQUIRES: executable_test import StdlibUnittest @@ -31,15 +37,31 @@ tupleCastTests.test("Adding/removing labels") { String(describing: anyToIntPoint((3, 4)))) expectEqual("(x: 5, y: 6)", String(describing: anyToIntPoint((x: 5, 6)))) + expectEqual("(x: 5, y: 6)", + String(describing: anyToIntPoint((5, y: 6)))) expectEqual("(1, 2)", String(describing: anyToInt2((1, 2)))) expectEqual("(3, 4)", String(describing: anyToInt2((x: 3, y: 4)))) expectEqual("(5, 6)", String(describing: anyToInt2((x: 5, 6)))) + expectEqual("(7, 8)", String(describing: anyToInt2((7, y: 8)))) expectEqual("(first: 1, 2, third: 3)", String(describing: anyToPartlyLabeled((1, 2, 3)))) } +tupleCastTests.test("Label checks on casting") { + expectTrue((x: 1, y: 2) is (Int, Int)) + expectTrue((x: 1, y: 2) is (x: Int, Int)) + expectTrue((x: 1, y: 2) is (Int, y: Int)) + expectTrue((x: 1, y: 2) is (x: Int, y: Int)) + + expectFalse((x: 1, y: 2) is (x: Int, z: Int)) + expectFalse((x: 1, y: 2) is (a: Int, y: Int)) + expectFalse((x: 1, y: 2) is (a: Int, z: Int)) + expectFalse((x: 1, y: 2) is (Int, z: Int)) + expectFalse((x: 1, y: 2) is (a: Int, Int)) +} + tupleCastTests.test("Incorrect labels conditional cast") { expectNil(anyToIntPointOpt((x: 1, z: 2))) expectEqual("Optional((x: 1, y: 2))", diff --git a/test/stdlib/Casts.swift b/test/stdlib/Casts.swift deleted file mode 100644 index 5e81f6643b154..0000000000000 --- a/test/stdlib/Casts.swift +++ /dev/null @@ -1,236 +0,0 @@ -// Casts.swift - Tests for conversion between types. -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -// ----------------------------------------------------------------------------- -/// -/// Contains tests for conversions between types which shouldn't trap. -/// -// ----------------------------------------------------------------------------- -// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-concurrency) -// REQUIRES: executable_test -// UNSUPPORTED: use_os_stdlib - -import StdlibUnittest -#if _runtime(_ObjC) -import Foundation -#endif - -private func blackhole(_ t: T) {} - -let CastsTests = TestSuite("Casts") - -// Test for SR-426: missing release for some types after failed conversion -CastsTests.test("No leak for failed tuple casts") { - let t: Any = (1, LifetimeTracked(0)) - expectFalse(t is Any.Type) -} - -protocol P {} -class ErrClass : Error { } - -CastsTests.test("No overrelease of existential boxes in failed casts") { - // Test for crash from SR-392 - // We fail casts of an existential box repeatedly - // to ensure it does not get over-released. - func bar(_ t: T) { - for _ in 0..<10 { - if case let a as P = t { - _ = a - } - } - } - - let err: Error = ErrClass() - bar(err) -} - -extension Int : P {} - -// Test for SR-7664: Inconsistent optional casting behaviour with generics -// Runtime failed to unwrap multiple levels of Optional when casting. -CastsTests.test("Multi-level optionals can be casted") { - func testSuccess(_ x: From, from: From.Type, to: To.Type) { - expectNotNil(x as? To) - } - func testFailure(_ x: From, from: From.Type, to: To.Type) { - expectNil(x as? To) - } - testSuccess(42, from: Int?.self, to: Int.self) - testSuccess(42, from: Int??.self, to: Int.self) - testSuccess(42, from: Int???.self, to: Int.self) - testSuccess(42, from: Int???.self, to: Int?.self) - testSuccess(42, from: Int???.self, to: Int??.self) - testSuccess(42, from: Int???.self, to: Int???.self) - testFailure(42, from: Int?.self, to: String.self) - testFailure(42, from: Int??.self, to: String.self) - testFailure(42, from: Int???.self, to: String.self) -} - -// Test for SR-9837: Optional.none not casting to Optional.none in generic context -CastsTests.test("Optional.none can be casted to Optional.none in generic context") { - func test(_ type: T.Type) -> T? { - return Any?.none as? T - } - - expectEqual(type(of: test(Bool.self)), Bool?.self) - expectEqual(type(of: test(Bool?.self)), Bool??.self) -} - -// Test for SR-3871: Cannot cast from ObjC existential without going through AnyObject -#if _runtime(_ObjC) -protocol P2 {} -CastsTests.test("Cast from ObjC existential to Protocol (SR-3871)") { - if #available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { - struct S: P2 {} - - class ObjCWrapper { - @objc dynamic let any: Any = S() - init() {} - } - let a = ObjCWrapper().any - expectTrue(a is P2) - // In SR-3871, the following cast failed (everything else here succeeded) - expectNotNil(a as? P2) - expectNotNil(a as? S) - let b = a as AnyObject - expectTrue(a is P2) - expectNotNil(b as? P2) - expectNotNil(b as? S) - } -} -#endif - -protocol P3 {} -CastsTests.test("Cast from Swift existential to Protocol") { - struct S: P3 {} - class SwiftWrapper { - let any: Any = S() - init() {} - } - let a = SwiftWrapper().any - expectTrue(a is P3) - expectNotNil(a as? P3) - expectNotNil(a as? S) - let b = a as AnyObject - expectTrue(b is P3) - expectNotNil(b as? P3) - expectNotNil(b as? S) -} - - -#if _runtime(_ObjC) -extension CFBitVector : P { - static func makeImmutable(from values: Array) -> CFBitVector { - return CFBitVectorCreate(/*allocator:*/ nil, values, values.count * 8) - } -} - -extension CFMutableBitVector { - static func makeMutable(from values: Array) -> CFMutableBitVector { - return CFBitVectorCreateMutableCopy( - /*allocator:*/ nil, - /*capacity:*/ 0, - CFBitVector.makeImmutable(from: values)) - } -} - -func isP(_ t: T) -> Bool { - return t is P -} - -CastsTests.test("Dynamic casts of CF types to protocol existentials") - .skip(.custom( - { !_isDebugAssertConfiguration() }, - reason: "This test behaves unpredictably in optimized mode.")) - .code { - expectTrue(isP(10 as Int)) - - // FIXME: SR-2289: dynamic casting of CF types to protocol existentials - // should work, but there is a bug in the runtime that prevents them from - // working. - expectFailure { - expectTrue(isP(CFBitVector.makeImmutable(from: [10, 20]))) - } - expectFailure { - expectTrue(isP(CFMutableBitVector.makeMutable(from: [10, 20]))) - } -} -#endif - -CastsTests.test("Any.Protocol") { - class C {} - struct S {} - func isAnyProtocol(_ type: T.Type) -> Bool { - let result = T.self is Any.Protocol - if result { - // `as!` should succeed if `is` does - blackhole(T.self as! Any.Protocol) - } - return result - } - func isAnyType(_ type: T.Type) -> Bool { - return T.self is Any.Type - } - func isType(_ type: T.Type, to: U.Type) -> Bool { - return T.self is U.Type - } - - expectTrue(Int.self is Any.Type) - expectNotNil(Int.self as? Any.Type) - expectTrue(isAnyType(Int.self)) - expectFalse(Int.self is Any.Protocol) - expectNil(Int.self as? Any.Protocol) - expectFalse(isAnyProtocol(Int.self)) - expectFalse(isType(Int.self, to: Any.self)) - - expectTrue(C.self is Any.Type) - expectNotNil(C.self as? Any.Type) - expectTrue(isAnyType(C.self)) - expectFalse(C.self is Any.Protocol) - expectNil(C.self as? Any.Protocol) - expectFalse(isAnyProtocol(C.self)) - expectFalse(isType(C.self, to: Any.self)) - - expectTrue(S.self is Any.Type) - expectNotNil(S.self as? Any.Type) - expectTrue(isAnyType(S.self)) - expectFalse(S.self is Any.Protocol) - expectNil(S.self as? Any.Protocol) - expectFalse(isAnyProtocol(S.self)) - expectFalse(isType(S.self, to: Any.self)) - - expectTrue(Any.self is Any.Type) - expectNotNil(Any.self as? Any.Type) - expectTrue(isAnyType(Any.self)) - expectTrue(Any.self is Any.Protocol) - expectNotNil(Any.self as? Any.Protocol) - expectTrue(isAnyProtocol(Any.self)) - expectTrue(isType(Any.self, to: Any.self)) - - expectTrue(Any?.self is Any.Type) - expectNotNil(Any?.self as? Any.Type) - expectTrue(isAnyType(Any?.self)) - expectFalse(Any?.self is Any.Protocol) - expectNil(Any?.self as? Any.Protocol) - expectFalse(isAnyProtocol(Any?.self)) - expectFalse(isType(Any?.self, to: Any.self)) -} - -CastsTests.test("Async function types") { - let asyncFnType: Any.Type = (() async -> Void).self - let fnType: Any.Type = (() -> Void).self - - expectTrue(fnType is (() -> Void).Type) - expectTrue(asyncFnType is (() async -> Void).Type) - expectFalse(fnType is (() async -> Void).Type) - expectFalse(asyncFnType is (() -> Void).Type) -} - -runAllTests() diff --git a/validation-test/Casting/BoxingCasts.swift.gyb b/validation-test/Casting/BoxingCasts.swift.gyb new file mode 100644 index 0000000000000..7ee19e67a85fb --- /dev/null +++ b/validation-test/Casting/BoxingCasts.swift.gyb @@ -0,0 +1,264 @@ +// BoxingCasts.swift - Tests for boxing/unboxing casts +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +// ----------------------------------------------------------------------------- +/// +/// Contains tests for existential, optional, and other casts that box/unbox values. +/// +// ----------------------------------------------------------------------------- +// RUN: %empty-directory(%t) +// +// RUN: %gyb %s -o %t/BoxingCasts.swift +// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -module-name a -swift-version 5 -Onone %t/BoxingCasts.swift -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %line-directive %t/BoxingCasts.swift -- %target-run %t/a.swift5.Onone.out +// +// Note: The RUN directives above override the default test optimizations. +// This test is deliberately run non-optimized in order to verify the +// behavior of runtime methods that may not be called for optimized casts. +// +// XXX FIXME XXX TODO XXX _Also_ build this with optimizations in order to +// verify compiler behaviors. +// +// REQUIRES: executable_test + +import StdlibUnittest +#if _runtime(_ObjC) +import Foundation +#endif + +fileprivate func runtimeCast (_ x: From, to: To.Type) -> To? { + return x as? To +} + +fileprivate func optional(_ x: T) -> Optional { + return runtimeCast(x, to: Optional.self)! +} + +fileprivate protocol FilePrivateProtocol {} +internal protocol InternalProtocol {} +public protocol PublicProtocol {} +protocol UnimplementedProtocol {} + +fileprivate enum EmptyEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { } + +fileprivate enum SingleCaseEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case case0 + init() {self = .case0} +} + +fileprivate enum TrivialPayloadEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case payloadCase(Int) + init() {self = .payloadCase(42)} +} + +extension TrivialPayloadEnum: Hashable {} + +fileprivate enum MultiPayloadEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case case0(String) +case case1(Int) + init() {self = .case1(42)} +} + +extension MultiPayloadEnum: Hashable {} + +fileprivate class ClassInt: FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) {value = v} +} + +extension ClassInt: Equatable, Hashable { + static func ==(left: ClassInt, right: ClassInt) -> Bool {left.value == right.value} + func hash(into hasher: inout Hasher) { value.hash(into: &hasher) } +} + +fileprivate struct StructInt: FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) { value = v} +} + +extension StructInt: Hashable, Equatable { } + +#if _runtime(_ObjC) +fileprivate class OCClassInt: NSObject, FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) { value = v} +} +#endif + +let BoxingCasts = TestSuite("BoxingCasts") + +%{ +import random +# The test body goes into a named function and the test case just invokes that +# function by name. This makes debugging easier, since it's easier to set break +# points on named functions than on arbitrary closures. +# The function names are included in the test name +# for ease of reference. +testNumber = 0 +def testFunctionName(): + return "test{number}".format(number=testNumber) +def nextTestNumber(): + global testNumber + testNumber += 1 + +# Type used for intermediate casts. The base object gets +# cast to one or more of these before the final test. +class Box: + def __init__(self, name, typeName=None, cast=None): + self.name = name + self.typeName = typeName or name + self.cast_template = cast or "runtimeCast({expr}, to: {typeName}.self)!" + def cast_oper(self, expr): + return self.cast_template.format(expr=expr, typeName=self.typeName) + +anyHashableBox = Box(name="AnyHashable") +all_boxes = [ + Box(name="Any", typeName="Any"), + Box(name="AnyStatic", cast="({expr} as Any)"), + Box(name="AnyObject"), + Box(name="SwiftValueBox", cast="_bridgeAnythingToObjectiveC({expr})"), + Box(name="Optional", cast="optional({expr})") +] +protocol_boxes = [ + Box(name="PublicProtocol"), +# Box(name="FilePrivateProtocol"), # Blocked by SR-2620 aka rdar://28281488 + Box(name="InternalProtocol"), +] + +# Describes a base object that will be subject to a variety of casts +default_protocols = [ + "PublicProtocol", + "InternalProtocol", + # "FilePrivateProtocol" # Blocked by SR-2620 aka rdar://28281488 +] + +class Contents: + def __init__(self, name, constructor=None, extra_targets=[], hashable=True, roundtrips=True, protocols=default_protocols, objc_only=False): + self.name = name + self.constructor = constructor or "{name}()".format(name=name) + self.objc_only = objc_only + + self.targets = ["Any"] + self.targets.extend(protocols) + self.targets.extend(extra_targets) + if roundtrips: + self.targets.append(self.name) + + self.boxes = [] + self.boxes.extend(all_boxes) + self.boxes.extend([Box(name=n) for n in protocols]) + if hashable: + self.boxes.append(anyHashableBox) + +contents = [ + Contents(name="StructInt", + # extra_targets=["StructInt?"], + ), + Contents(name="StructInt?", + constructor="Optional.some(StructInt())", + extra_targets=["StructInt"], + roundtrips=False, # Compiler bug rejects roundtrip cast T? => Any => T? + ), + Contents(name="ClassInt"), + Contents(name="OCClassInt", objc_only=True), + Contents(name="SingleCaseEnum"), + Contents(name="TrivialPayloadEnum"), + Contents(name="TrivialPayloadEnum"), + Contents(name="MultiPayloadEnum"), + Contents(name="StructInt.Type", + constructor="StructInt.self", + hashable=False, + protocols=[], + ), + Contents(name="StructInt.Type?", + constructor="Optional.some(StructInt.self)", + hashable=False, + protocols=[], + extra_targets=["StructInt.Type"], + roundtrips=False, # Compiler bug rejects roundtrip cast T? => Any => T? + ), + Contents(name="PublicProtocol.Protocol", + constructor="PublicProtocol.self", + hashable=False, + protocols=[], + ), +] + +# Code below generates a separate test case for each combination of content, +# target type, and one or more box/intermediate types. +}% + +% for content in contents: +% if content.objc_only: +#if _runtime(_ObjC) +% end +% for target in content.targets: +% for box in content.boxes: +% nextTestNumber() +BoxingCasts.test("${testFunctionName()}(): Casting ${box.name}(${content.name}) to ${target}") { + // TODO: Selectively enable/disable cases that work with earlier stdlib + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + ${testFunctionName()}() + } +} +func ${testFunctionName()}() { + let a = ${content.constructor} + let b = ${box.cast_oper("a")} +% # // Skip trivial cast from T? to T +% if not (content.name == target and box.name == "Optional"): +% # // Skip trivial cast from protocol box to protocol +% if box.name != target: +% # // Skip trivial cast from T? => P +% if not (target.endswith("Protocol") and box.name == "Optional"): + let c = /* ${box.name}(${content.name})) */ b as? ${target} + expectNotNil(c) +% end +% end +% end + let d = runtimeCast(/* ${box.name}(${content.name}) */ b, to: ${target}.self) + expectNotNil(d) +} + +% for innerBox in [random.choice(content.boxes)]: +% nextTestNumber() +BoxingCasts.test("${testFunctionName()}(): Casting ${box.name}(${innerBox.name}(${content.name})) to ${target}") { + // TODO: Selectively enable/disable cases that work with earlier stdlib + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + ${testFunctionName()}() + } +} +func ${testFunctionName()}() { + let a = ${content.constructor} + let b = ${innerBox.cast_oper("a")} + let c = ${box.cast_oper("b")} +% # // Skip trivial cast from T? to T +% if not (innerBox.name == target and box.name == "Optional"): +% # // Skip trivial cast from protocol box to protocol +% if box.name != target: + let d = /* ${box.name}(${innerBox.name}(${content.name})) */ c as? ${target} + expectNotNil(d) +% end +% end + let e = runtimeCast(/* ${box.name}(${innerBox.name}(${content.name})) */ c, to: ${target}.self) + expectNotNil(e) +} +% end +% end +% end +% if content.objc_only: +#endif +% end +% end + +runAllTests() From 9665091121fb29edba277bc9782a30db8b70e507 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 27 Aug 2020 11:51:00 -0700 Subject: [PATCH 388/663] [CSBindings] Don't attempt to join types that contain holes --- lib/AST/TypeJoinMeet.cpp | 3 +++ lib/Sema/CSBindings.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp index a5609f8b669fb..468cb6810fc1a 100644 --- a/lib/AST/TypeJoinMeet.cpp +++ b/lib/AST/TypeJoinMeet.cpp @@ -87,6 +87,9 @@ struct TypeJoin : CanTypeVisitor { assert(!first->hasTypeVariable() && !second->hasTypeVariable() && "Cannot compute join of types involving type variables"); + assert(!first->hasHole() && !second->hasHole() && + "Cannot compute join of types involving type holes"); + assert(first->getWithoutSpecifierType()->isEqual(first) && "Expected simple type!"); assert(second->getWithoutSpecifierType()->isEqual(second) && diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 807a86b01a85a..a82b389991788 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -481,6 +481,7 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding( if (binding.Kind == AllowedBindingKind::Supertypes && !binding.BindingType->hasUnresolvedType() && !binding.BindingType->hasTypeVariable() && + !binding.BindingType->hasHole() && !binding.BindingType->hasUnboundGenericType() && !binding.hasDefaultedLiteralProtocol() && !binding.isDefaultableBinding() && allowJoinMeet) { From 83b50cd8e360d78dc320fd70020c5a08899994cb Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Thu, 27 Aug 2020 11:53:33 -0700 Subject: [PATCH 389/663] [AutoDiff] Add missing `withoutDerivative(at:)` fix-its. (#33660) Add `withoutDerivative(at:)` fix-its for errors regarding non-differentiable arguments and results. --- .../Differentiation/JVPCloner.cpp | 22 ++++++++++++++----- .../Differentiation/VJPCloner.cpp | 21 +++++++++++++----- ...erentiation_control_flow_diagnostics.swift | 2 +- .../differentiation_diagnostics.swift | 8 +++---- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index d7b8caa102e53..2586e5ac6ad2e 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -553,9 +553,14 @@ class JVPCloner::Implementation final if (!originalFnTy->getParameters()[paramIndex] .getSILStorageInterfaceType() .isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - ai->getArgumentsWithoutIndirectResults()[paramIndex], - invoker, diag::autodiff_nondifferentiable_argument); + auto arg = ai->getArgumentsWithoutIndirectResults()[paramIndex]; + auto startLoc = arg.getLoc().getStartSourceLoc(); + auto endLoc = arg.getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + arg, invoker, diag::autodiff_nondifferentiable_argument) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -573,9 +578,14 @@ class JVPCloner::Implementation final .getSILStorageInterfaceType(); } if (!remappedResultType.isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - origCallee, invoker, - diag::autodiff_nondifferentiable_result); + auto startLoc = ai->getLoc().getStartSourceLoc(); + auto endLoc = ai->getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + origCallee, invoker, + diag::autodiff_nondifferentiable_result) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index 7279ce914d83c..f58db200debe9 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -457,9 +457,14 @@ class VJPCloner::Implementation final if (!originalFnTy->getParameters()[paramIndex] .getSILStorageInterfaceType() .isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - ai->getArgumentsWithoutIndirectResults()[paramIndex], invoker, - diag::autodiff_nondifferentiable_argument); + auto arg = ai->getArgumentsWithoutIndirectResults()[paramIndex]; + auto startLoc = arg.getLoc().getStartSourceLoc(); + auto endLoc = arg.getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + arg, invoker, diag::autodiff_nondifferentiable_argument) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -477,8 +482,14 @@ class VJPCloner::Implementation final .getSILStorageInterfaceType(); } if (!remappedResultType.isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - origCallee, invoker, diag::autodiff_nondifferentiable_result); + auto startLoc = ai->getLoc().getStartSourceLoc(); + auto endLoc = ai->getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + origCallee, invoker, + diag::autodiff_nondifferentiable_result) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } diff --git a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift index 331a48a425c2c..5248811b04aa0 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift @@ -171,7 +171,7 @@ func loop_array(_ array: [Float]) -> Float { var result: Float = 1 // TODO(TF-957): Improve non-differentiability errors for for-in loops // (`Collection.makeIterator` and `IteratorProtocol.next`). - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{12-12=withoutDerivative(at: }} {{17-17=)}} for x in array { result = result * x } diff --git a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift index cbb4e0fa132f7..22d3fca6a17c3 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift @@ -301,14 +301,14 @@ struct TF_687 : Differentiable { } } // expected-error @+2 {{function is not differentiable}} -// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} +// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{78-78=withoutDerivative(at: }} {{79-79=)}} let _: @differentiable (Float) -> TF_687 = { x in TF_687(x, dummy: x) } // expected-error @+1 {{function is not differentiable}} @differentiable // expected-note @+1 {{when differentiating this function definition}} func roundingGivesError(x: Float) -> Float { - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{16-16=withoutDerivative(at: }} {{22-22=)}} return Float(Int(x)) } @@ -688,7 +688,7 @@ func differentiableProjectedValueAccess(_ s: Struct) -> Float { // expected-note @+2 {{when differentiating this function definition}} @differentiable func projectedValueAccess(_ s: Struct) -> Float { - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{3-3=withoutDerivative(at: }} {{7-7=)}} s.$y.wrappedValue } @@ -714,7 +714,7 @@ func modify(_ s: Struct, _ x: Float) -> Float { func tupleArrayLiteralInitialization(_ x: Float, _ y: Float) -> Float { // `Array<(Float, Float)>` does not conform to `Differentiable`. let array = [(x * y, x * y)] - // expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{10-10=withoutDerivative(at: }} {{15-15=)}} return array[0].0 } From 103b61c8be901bf003c37faaae241a9af2cc2db1 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Thu, 27 Aug 2020 12:06:25 -0700 Subject: [PATCH 390/663] ABIChecker: rename argument -protocol-requirement-white-list to -protocol-requirement-allow-list --- test/api-digester/compare-clang-dump.swift | 2 +- .../swift-api-digester/swift-api-digester.cpp | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/api-digester/compare-clang-dump.swift b/test/api-digester/compare-clang-dump.swift index cdb59d1bf93a4..3cafec46d6288 100644 --- a/test/api-digester/compare-clang-dump.swift +++ b/test/api-digester/compare-clang-dump.swift @@ -3,7 +3,7 @@ // RUN: %empty-directory(%t.module-cache) // RUN: %api-digester -dump-sdk -module Foo -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo -avoid-location // RUN: %api-digester -dump-sdk -module Foo -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo-new-version -avoid-location -// RUN: %api-digester -diagnose-sdk -protocol-requirement-white-list %S/Inputs/Foo-prot-allowlist.txt -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result +// RUN: %api-digester -diagnose-sdk -protocol-requirement-allow-list %S/Inputs/Foo-prot-allowlist.txt -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result // RUN: %clang -E -P -x c %S/Outputs/Foo-diff.txt -o - | sed '/^\s*$/d' > %t.expected // RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index 2b089bf718c5f..4980d39d15e09 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -72,7 +72,7 @@ ModuleList("module-list-file", llvm::cl::cat(Category)); static llvm::cl::opt -ProtReqWhiteList("protocol-requirement-white-list", +ProtReqAllowList("protocol-requirement-allow-list", llvm::cl::desc("File containing a new-line separated list of protocol names"), llvm::cl::cat(Category)); @@ -1074,7 +1074,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { SDKContext &Ctx; UpdatedNodesMap &UpdateMap; - llvm::StringSet<> ProtocolReqWhitelist; + llvm::StringSet<> ProtocolReqAllowlist; SDKNodeRoot *LeftRoot; SDKNodeRoot *RightRoot; @@ -1123,10 +1123,10 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { public: PrunePass(SDKContext &Ctx): Ctx(Ctx), UpdateMap(Ctx.getNodeUpdateMap()) {} - PrunePass(SDKContext &Ctx, llvm::StringSet<> prWhitelist): + PrunePass(SDKContext &Ctx, llvm::StringSet<> prAllowlist): Ctx(Ctx), UpdateMap(Ctx.getNodeUpdateMap()), - ProtocolReqWhitelist(std::move(prWhitelist)) {} + ProtocolReqAllowlist(std::move(prAllowlist)) {} void diagnoseMissingAvailable(SDKNodeDecl *D) { // For extensions of external types, we diagnose individual member's missing @@ -1178,7 +1178,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { ShouldComplain = false; } if (ShouldComplain && - ProtocolReqWhitelist.count(getParentProtocolName(D))) { + ProtocolReqAllowlist.count(getParentProtocolName(D))) { // Ignore protocol requirement additions if the protocol has been added // to the allowlist. ShouldComplain = false; @@ -2311,7 +2311,7 @@ createDiagConsumer(llvm::raw_ostream &OS, bool &FailOnError) { static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, SDKNodeRoot *RightModule, StringRef OutputPath, - llvm::StringSet<> ProtocolReqWhitelist) { + llvm::StringSet<> ProtocolReqAllowlist) { assert(LeftModule); assert(RightModule); llvm::raw_ostream *OS = &llvm::errs(); @@ -2334,7 +2334,7 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, RightModule->getJsonFormatVersion())); TypeAliasDiffFinder(LeftModule, RightModule, Ctx.getTypeAliasUpdateMap()).search(); - PrunePass Prune(Ctx, std::move(ProtocolReqWhitelist)); + PrunePass Prune(Ctx, std::move(ProtocolReqAllowlist)); Prune.pass(LeftModule, RightModule); ChangeRefinementPass RefinementPass(Ctx.getNodeUpdateMap()); RefinementPass.pass(LeftModule, RightModule); @@ -2347,7 +2347,7 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, StringRef OutputPath, CheckerOptions Opts, - llvm::StringSet<> ProtocolReqWhitelist) { + llvm::StringSet<> ProtocolReqAllowlist) { if (!fs::exists(LeftPath)) { llvm::errs() << LeftPath << " does not exist\n"; return 1; @@ -2362,7 +2362,7 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, SwiftDeclCollector RightCollector(Ctx); RightCollector.deSerialize(RightPath); diagnoseModuleChange(Ctx, LeftCollector.getSDKRoot(), RightCollector.getSDKRoot(), - OutputPath, std::move(ProtocolReqWhitelist)); + OutputPath, std::move(ProtocolReqAllowlist)); return options::CompilerStyleDiags && Ctx.getDiags().hadAnyError() ? 1 : 0; } @@ -2837,9 +2837,9 @@ int main(int argc, char *argv[]) { case ActionType::MigratorGen: case ActionType::DiagnoseSDKs: { ComparisonInputMode Mode = checkComparisonInputMode(); - llvm::StringSet<> protocolWhitelist; - if (!options::ProtReqWhiteList.empty()) { - if (readFileLineByLine(options::ProtReqWhiteList, protocolWhitelist)) + llvm::StringSet<> protocolAllowlist; + if (!options::ProtReqAllowList.empty()) { + if (readFileLineByLine(options::ProtReqAllowList, protocolAllowlist)) return 1; } if (options::Action == ActionType::MigratorGen) { @@ -2853,21 +2853,21 @@ int main(int argc, char *argv[]) { return diagnoseModuleChange(options::SDKJsonPaths[0], options::SDKJsonPaths[1], options::OutputFile, Opts, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } case ComparisonInputMode::BaselineJson: { SDKContext Ctx(Opts); return diagnoseModuleChange(Ctx, getBaselineFromJson(argv[0], Ctx), getSDKRoot(argv[0], Ctx, false), options::OutputFile, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } case ComparisonInputMode::BothLoad: { SDKContext Ctx(Opts); return diagnoseModuleChange(Ctx, getSDKRoot(argv[0], Ctx, true), getSDKRoot(argv[0], Ctx, false), options::OutputFile, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } } } From 80560dab2582172e0684080382586591a55cb342 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Thu, 27 Aug 2020 22:17:09 +0300 Subject: [PATCH 391/663] CSGen: Infer generic arguments in explicit closure result types --- lib/Sema/CSGen.cpp | 14 +++++++++----- test/Constraints/closures.swift | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0891e23c6474c..37bc51c12508b 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2073,12 +2073,14 @@ namespace { return resolveTypeReferenceInExpression( closure->getExplicitResultTypeRepr(), - TypeResolverContext::InExpression, nullptr); + TypeResolverContext::InExpression, + // Introduce type variables for unbound generics. + OpenUnboundGenericType( + CS, CS.getConstraintLocator(closure, + ConstraintLocator::ClosureResult))); }; Type resultTy; - auto *resultLoc = - CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult); if (auto explicityTy = getExplicitResultType()) { resultTy = explicityTy; } else { @@ -2099,9 +2101,11 @@ namespace { // If this is a multi-statement closure, let's mark result // as potential hole right away. resultTy = CS.createTypeVariable( - resultLoc, + CS.getConstraintLocator(closure, + ConstraintLocator::ClosureResult), shouldTypeCheckInEnclosingExpression(closure) - ? 0 : TVO_CanBindToHole); + ? 0 + : TVO_CanBindToHole); } } diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index b6f99b7350729..0b77ce6ac87b2 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -1030,3 +1030,15 @@ func sr12815() { .doesntExist2() { $0 } } } + +// Make sure we can infer generic arguments in an explicit result type. +let explicitUnboundResult1 = { () -> Array in [0] } +let explicitUnboundResult2: (Array) -> Array = { + (arr: Array) -> Array in [0] +} +// FIXME: Should we prioritize the contextual result type and infer Array +// rather than using a type variable in these cases? +// expected-error@+1 {{unable to infer closure type in the current context}} +let explicitUnboundResult3: (Array) -> Array = { + (arr: Array) -> Array in [true] +} From 61d86d5fd2652103cb09d6b2fe7dcb48c3696104 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Thu, 27 Aug 2020 22:23:19 +0300 Subject: [PATCH 392/663] [NFC] CSGen: Clean up some flow in inferClosureType --- lib/Sema/CSGen.cpp | 70 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 37bc51c12508b..f4dff643717aa 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2062,52 +2062,38 @@ namespace { // parameter or return type is omitted, a fresh type variable is used to // stand in for that parameter or return type, allowing it to be inferred // from context. - auto getExplicitResultType = [&]() -> Type { - if (!closure->hasExplicitResultType()) { - return Type(); - } + Type resultTy = [&] { + if (closure->hasExplicitResultType()) { + if (auto declaredTy = closure->getExplicitResultType()) { + return declaredTy; + } - if (auto declaredTy = closure->getExplicitResultType()) { - return declaredTy; + const auto resolvedTy = resolveTypeReferenceInExpression( + closure->getExplicitResultTypeRepr(), + TypeResolverContext::InExpression, + // Introduce type variables for unbound generics. + OpenUnboundGenericType( + CS, CS.getConstraintLocator( + closure, ConstraintLocator::ClosureResult))); + if (resolvedTy) + return resolvedTy; } - return resolveTypeReferenceInExpression( - closure->getExplicitResultTypeRepr(), - TypeResolverContext::InExpression, - // Introduce type variables for unbound generics. - OpenUnboundGenericType( - CS, CS.getConstraintLocator(closure, - ConstraintLocator::ClosureResult))); - }; - - Type resultTy; - if (auto explicityTy = getExplicitResultType()) { - resultTy = explicityTy; - } else { - auto getContextualResultType = [&]() -> Type { - if (auto contextualType = CS.getContextualType(closure)) { - if (auto fnType = contextualType->getAs()) - return fnType->getResult(); - } - return Type(); - }; - - if (auto contextualResultTy = getContextualResultType()) { - resultTy = contextualResultTy; - } else { - // If no return type was specified, create a fresh type - // variable for it and mark it as possible hole. - // - // If this is a multi-statement closure, let's mark result - // as potential hole right away. - resultTy = CS.createTypeVariable( - CS.getConstraintLocator(closure, - ConstraintLocator::ClosureResult), - shouldTypeCheckInEnclosingExpression(closure) - ? 0 - : TVO_CanBindToHole); + if (auto contextualType = CS.getContextualType(closure)) { + if (auto fnType = contextualType->getAs()) + return fnType->getResult(); } - } + + // If no return type was specified, create a fresh type + // variable for it and mark it as possible hole. + // + // If this is a multi-statement closure, let's mark result + // as potential hole right away. + return Type(CS.createTypeVariable( + CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult), + shouldTypeCheckInEnclosingExpression(closure) ? 0 + : TVO_CanBindToHole)); + }(); return FunctionType::get(closureParams, resultTy, extInfo); } From 84c50655472e5bf5329ddc5e3d9f0386acfbd07e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 27 Aug 2020 12:48:41 -0700 Subject: [PATCH 393/663] [SR-13461] Relax An Assert This assert doesn't consider reference storage types in its predicate. Look through them since they're not relevant to the type consistency check it's trying to pick out. --- lib/SILGen/SILGenConstructor.cpp | 8 +++----- .../compiler_crashers_2_fixed/sr13461.swift | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 validation-test/compiler_crashers_2_fixed/sr13461.swift diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 0aef4de8034b3..0f4866879fb90 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -216,11 +216,9 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, .forwardInto(SGF, Loc, init.get()); ++elti; } else { -#ifndef NDEBUG - assert( - field->getType()->isEqual(field->getParentInitializer()->getType()) - && "Checked by sema"); -#endif + assert(field->getType()->getReferenceStorageReferent()->isEqual( + field->getParentInitializer()->getType()) && + "Initialization of field with mismatched type!"); // Cleanup after this initialization. FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); diff --git a/validation-test/compiler_crashers_2_fixed/sr13461.swift b/validation-test/compiler_crashers_2_fixed/sr13461.swift new file mode 100644 index 0000000000000..b6bda64bdce53 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr13461.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -o /dev/null %s +// REQUIRES: asserts + +final class Klass { + static var current: Klass { + fatalError() + } +} +private struct Build { + let val: T + unowned let unownedBinding = Klass.current + unowned(unsafe) let unownedUnsafeBinding = Klass.current + weak var weakBinding = Klass.current +} +private func phase(_ val: T) -> Build { + return Build(val: val) +} From c890cdd1a379db55e51d7ec8657d55b6dc2e7ba4 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Mon, 27 Jul 2020 22:01:54 -0700 Subject: [PATCH 394/663] [AST] Add functionality for computing Clang types for SIL functions. --- include/swift/AST/ASTContext.h | 14 ++++++++++ lib/AST/ASTContext.cpp | 24 ++++++++++++---- lib/AST/ClangTypeConverter.cpp | 51 ++++++++++++++++++++++++++++++++++ lib/AST/ClangTypeConverter.h | 5 ++++ lib/IRGen/GenClangType.cpp | 10 +++---- 5 files changed, 94 insertions(+), 10 deletions(-) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 9281ebcf55c2b..e3ecfbb158dfb 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -62,6 +62,7 @@ namespace swift { class BoundGenericType; class ClangModuleLoader; class ClangNode; + class ClangTypeConverter; class ConcreteDeclRef; class ConstructorDecl; class Decl; @@ -586,6 +587,10 @@ class ASTContext final { Type getBridgedToObjC(const DeclContext *dc, Type type, Type *bridgedValueType = nullptr) const; +private: + ClangTypeConverter &getClangTypeConverter(); + +public: /// Get the Clang type corresponding to a Swift function type. /// /// \param params The function parameters. @@ -595,6 +600,15 @@ class ASTContext final { getClangFunctionType(ArrayRef params, Type resultTy, FunctionTypeRepresentation trueRep); + /// Get the canonical Clang type corresponding to a SIL function type. + /// + /// SIL analog of \c ASTContext::getClangFunctionType . + const clang::Type * + getCanonicalClangFunctionType( + ArrayRef params, Optional result, + const SILFunctionType::ExtInfo incompleteExtInfo, + SILFunctionType::Representation trueRep); + /// Get the Swift declaration that a Clang declaration was exported from, /// if applicable. const Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 633527ccf7735..b8a0f69ccd747 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4457,16 +4457,30 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type, return Type(); } -const clang::Type * -ASTContext::getClangFunctionType(ArrayRef params, - Type resultTy, - FunctionTypeRepresentation trueRep) { +ClangTypeConverter &ASTContext::getClangTypeConverter() { auto &impl = getImpl(); if (!impl.Converter) { auto *cml = getClangModuleLoader(); impl.Converter.emplace(*this, cml->getClangASTContext(), LangOpts.Target); } - return impl.Converter.getValue().getFunctionType(params, resultTy, trueRep); + return impl.Converter.getValue(); +} + +const clang::Type * +ASTContext::getClangFunctionType(ArrayRef params, + Type resultTy, + FunctionTypeRepresentation trueRep) { + return getClangTypeConverter().getFunctionType(params, resultTy, trueRep); +} + +const clang::Type * +ASTContext::getCanonicalClangFunctionType( + ArrayRef params, + Optional result, + SILFunctionType::ExtInfo incompleteExtInfo, + SILFunctionType::Representation trueRep) { + auto *ty = getClangTypeConverter().getFunctionType(params, result, trueRep); + return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr; } const Decl * diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index 2a08f78fb282e..9fd13f797798d 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -158,6 +158,57 @@ const clang::Type *ClangTypeConverter::getFunctionType( llvm_unreachable("invalid representation"); } +const clang::Type *ClangTypeConverter::getFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation repr) { + + // Using the interface type is sufficient as type parameters get mapped to + // `id`, since ObjC lightweight generics use type erasure. (See also: SE-0057) + auto resultClangTy = result.hasValue() + ? convert(result.getValue().getInterfaceType()) + : ClangASTContext.VoidTy; + + if (resultClangTy.isNull()) + return nullptr; + + SmallVector extParamInfos; + SmallVector paramsClangTy; + bool someParamIsConsumed = false; + for (auto &p : params) { + auto pc = convert(p.getInterfaceType()); + if (pc.isNull()) + return nullptr; + clang::FunctionProtoType::ExtParameterInfo extParamInfo; + if (p.isConsumed()) { + someParamIsConsumed = true; + extParamInfo = extParamInfo.withIsConsumed(true); + } + extParamInfos.push_back(extParamInfo); + paramsClangTy.push_back(pc); + } + + clang::FunctionProtoType::ExtProtoInfo info(clang::CallingConv::CC_C); + if (someParamIsConsumed) + info.ExtParameterInfos = extParamInfos.begin(); + auto fn = ClangASTContext.getFunctionType(resultClangTy, paramsClangTy, info); + if (fn.isNull()) + return nullptr; + + switch (repr) { + case SILFunctionType::Representation::CFunctionPointer: + return ClangASTContext.getPointerType(fn).getTypePtr(); + case SILFunctionType::Representation::Block: + return ClangASTContext.getBlockPointerType(fn).getTypePtr(); + case SILFunctionType::Representation::Thick: + case SILFunctionType::Representation::Thin: + case SILFunctionType::Representation::Method: + case SILFunctionType::Representation::ObjCMethod: + case SILFunctionType::Representation::WitnessMethod: + case SILFunctionType::Representation::Closure: + llvm_unreachable("Expected a C-compatible representation."); + } +} + clang::QualType ClangTypeConverter::convertMemberType(NominalTypeDecl *DC, StringRef memberName) { auto memberTypeDecl = cast( diff --git a/lib/AST/ClangTypeConverter.h b/lib/AST/ClangTypeConverter.h index 450b9e30cf19a..e41a824163312 100644 --- a/lib/AST/ClangTypeConverter.h +++ b/lib/AST/ClangTypeConverter.h @@ -74,6 +74,11 @@ class ClangTypeConverter : ArrayRef params, Type resultTy, AnyFunctionType::Representation repr); + /// Compute the C function type for a SIL function type. + const clang::Type *getFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation repr); + /// Check whether the given Clang declaration is an export of a Swift /// declaration introduced by this converter, and if so, return the original /// Swift declaration. diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index bc788fab6904a..8bc35dd99c134 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -132,10 +132,10 @@ namespace { /// ABI. class GenClangType : public CanTypeVisitor { IRGenModule &IGM; - ClangTypeConverter &Converter; + irgen::ClangTypeConverter &Converter; public: - GenClangType(IRGenModule &IGM, ClangTypeConverter &converter) + GenClangType(IRGenModule &IGM, irgen::ClangTypeConverter &converter) : IGM(IGM), Converter(converter) {} const clang::ASTContext &getClangASTContext() const { @@ -264,8 +264,8 @@ static clang::CanQualType getClangBuiltinTypeFromTypedef( } clang::CanQualType -ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM, - CanStructType type) { +irgen::ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM, + CanStructType type) { // Handle builtin types by adding entries to the cache that reverse // the mapping done by the importer. We could try to look at the // members of the struct instead, but even if that's ABI-equivalent @@ -748,7 +748,7 @@ clang::CanQualType GenClangType::visitType(CanType type) { llvm_unreachable("Unexpected type in Clang type generation."); } -clang::CanQualType ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { +clang::CanQualType irgen::ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { // Look in the cache. auto it = Cache.find(type); if (it != Cache.end()) { From 1807412e85f5e9fc274e254ad029ebb199f8a3fc Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 18 Aug 2020 14:44:13 -0700 Subject: [PATCH 395/663] [Serialization] Allow different Clang types in deserialization. We could've stored a function pointer or a block pointer or a function reference. --- lib/Serialization/Deserialization.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index ed98ea9976f26..724aef5da6b76 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5413,16 +5413,12 @@ class TypeDeserializer { if (!diffKind.hasValue()) MF.fatal(); - const clang::FunctionType *clangFunctionType = nullptr; + const clang::Type *clangFunctionType = nullptr; if (clangFunctionTypeID) { auto clangType = MF.getClangType(clangFunctionTypeID); if (!clangType) return clangType.takeError(); - // FIXME: allow block pointers here. - clangFunctionType = - dyn_cast_or_null(clangType.get()); - if (!clangFunctionType) - MF.fatal(); + clangFunctionType = clangType.get(); } auto extInfo = From eaac23fdd4dbb2f35c160dabf89ea54557701950 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 18 Aug 2020 15:14:51 -0700 Subject: [PATCH 396/663] [NFC] Remove ASTExtInfo::assertIsFunctionType in favor of checkInvariants. Invariants should be checked only when calling build(), not when the builder itself is created. --- include/swift/AST/ExtInfo.h | 10 +--------- lib/AST/ExtInfo.cpp | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 51592181aabf2..02c78efccf68f 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -194,16 +194,8 @@ class ASTExtInfoBuilder { using Representation = FunctionTypeRepresentation; - static void assertIsFunctionType(const clang::Type *); - ASTExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo) - : bits(bits), clangTypeInfo(clangTypeInfo) { - // TODO: [clang-function-type-serialization] Once we start serializing - // the Clang type, we should also assert that the pointer is non-null. - auto Rep = Representation(bits & RepresentationMask); - if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type) - assertIsFunctionType(clangTypeInfo.type); - } + : bits(bits), clangTypeInfo(clangTypeInfo) {} public: // Constructor with all defaults. diff --git a/lib/AST/ExtInfo.cpp b/lib/AST/ExtInfo.cpp index a75a3ff1d9f5e..5b779920ace0b 100644 --- a/lib/AST/ExtInfo.cpp +++ b/lib/AST/ExtInfo.cpp @@ -19,6 +19,20 @@ #include "clang/AST/Type.h" +static void assertIsFunctionType(const clang::Type *type) { +#ifndef NDEBUG + if (!(type->isFunctionPointerType() || type->isBlockPointerType() || + type->isFunctionReferenceType())) { + llvm::SmallString<256> buf; + llvm::raw_svector_ostream os(buf); + os << "Expected a Clang function type wrapped in a pointer type or " + << "a block pointer type but found:\n"; + type->dump(os); + llvm_unreachable(os.str().data()); + } +#endif +} + namespace swift { // MARK: - ClangTypeInfo @@ -53,23 +67,12 @@ void ClangTypeInfo::dump(llvm::raw_ostream &os) const { // MARK: - ASTExtInfoBuilder -void ASTExtInfoBuilder::assertIsFunctionType(const clang::Type *type) { -#ifndef NDEBUG - if (!(type->isFunctionPointerType() || type->isBlockPointerType() || - type->isFunctionReferenceType())) { - SmallString<256> buf; - llvm::raw_svector_ostream os(buf); - os << "Expected a Clang function type wrapped in a pointer type or " - << "a block pointer type but found:\n"; - type->dump(os); - llvm_unreachable(os.str().data()); - } -#endif - return; -} - void ASTExtInfoBuilder::checkInvariants() const { - // TODO: Add validation checks here while making sure things don't blow up. + // TODO: [clang-function-type-serialization] Once we start serializing + // the Clang type, we should also assert that the pointer is non-null. + auto Rep = Representation(bits & RepresentationMask); + if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type) + assertIsFunctionType(clangTypeInfo.type); } // MARK: - ASTExtInfo From 8da4d53d2c3a0b3976b14d0e0dc38d1144191fe8 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 18 Aug 2020 16:09:32 -0700 Subject: [PATCH 397/663] [NFC] Use ClangTypeInfo's implicit null state instead of an extra Optional. --- include/swift/AST/ExtInfo.h | 19 +++++-------------- include/swift/AST/Types.h | 2 +- lib/AST/ASTContext.cpp | 12 ++++++------ lib/AST/ASTPrinter.cpp | 6 +++--- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 02c78efccf68f..6b2bc1b8bf7c5 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -246,10 +246,7 @@ class ASTExtInfoBuilder { DifferentiabilityKind::NonDifferentiable; } - /// Get the underlying ClangTypeInfo value if it is not the default value. - Optional getClangTypeInfo() const { - return clangTypeInfo.empty() ? Optional() : clangTypeInfo; - } + ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; } constexpr SILFunctionTypeRepresentation getSILRepresentation() const { unsigned rawRep = bits & RepresentationMask; @@ -396,9 +393,7 @@ class ASTExtInfo { constexpr bool isDifferentiable() const { return builder.isDifferentiable(); } - Optional getClangTypeInfo() const { - return builder.getClangTypeInfo(); - } + ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); } constexpr bool hasSelfParam() const { return builder.hasSelfParam(); } @@ -558,10 +553,8 @@ class SILExtInfoBuilder { DifferentiabilityKind::NonDifferentiable; } - /// Get the underlying ClangTypeInfo value if it is not the default value. - Optional getClangTypeInfo() const { - return clangTypeInfo.empty() ? Optional() : clangTypeInfo; - } + /// Get the underlying ClangTypeInfo value. + ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; } constexpr bool hasSelfParam() const { switch (getRepresentation()) { @@ -689,9 +682,7 @@ class SILExtInfo { constexpr bool isDifferentiable() const { return builder.isDifferentiable(); } - Optional getClangTypeInfo() const { - return builder.getClangTypeInfo(); - } + ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); } constexpr bool hasSelfParam() const { return builder.hasSelfParam(); } diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 1dd1aed9bd772..863cce2503988 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -2872,7 +2872,7 @@ class AnyFunctionType : public TypeBase { unsigned NumParams, ExtInfo Info) : TypeBase(Kind, CanTypeContext, properties), Output(Output) { Bits.AnyFunctionType.ExtInfoBits = Info.getBits(); - Bits.AnyFunctionType.HasClangTypeInfo = Info.getClangTypeInfo().hasValue(); + Bits.AnyFunctionType.HasClangTypeInfo = !Info.getClangTypeInfo().empty(); Bits.AnyFunctionType.NumParams = NumParams; assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!"); // The use of both assert() and static_assert() is intentional. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b8a0f69ccd747..ce4f9c980bf6f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3131,16 +3131,16 @@ FunctionType *FunctionType::get(ArrayRef params, return funcTy; } - Optional clangTypeInfo = info.getClangTypeInfo(); + auto clangTypeInfo = info.getClangTypeInfo(); size_t allocSize = totalSizeToAlloc( - params.size(), clangTypeInfo.hasValue() ? 1 : 0); + params.size(), clangTypeInfo.empty() ? 0 : 1); void *mem = ctx.Allocate(allocSize, alignof(FunctionType), arena); bool isCanonical = isFunctionTypeCanonical(params, result); - if (clangTypeInfo.hasValue()) { + if (!clangTypeInfo.empty()) { if (ctx.LangOpts.UseClangFunctionTypes) - isCanonical &= clangTypeInfo->type->isCanonicalUnqualified(); + isCanonical &= clangTypeInfo.getType()->isCanonicalUnqualified(); else isCanonical = false; } @@ -3162,8 +3162,8 @@ FunctionType::FunctionType(ArrayRef params, std::uninitialized_copy(params.begin(), params.end(), getTrailingObjects()); auto clangTypeInfo = info.getClangTypeInfo(); - if (clangTypeInfo.hasValue()) - *getTrailingObjects() = clangTypeInfo.getValue(); + if (!clangTypeInfo.empty()) + *getTrailingObjects() = clangTypeInfo; } void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 58a220d54c776..a2eea55434aa4 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3629,7 +3629,7 @@ void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) { auto *cml = Ctx.getClangModuleLoader(); SmallString<64> buf; llvm::raw_svector_ostream os(buf); - info.getClangTypeInfo().getValue().printType(cml, os); + info.getClangTypeInfo().printType(cml, os); Printer << ", cType: " << QuotedString(os.str()); } @@ -4054,7 +4054,7 @@ class TypePrinter : public TypeVisitor { case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || !info.getClangTypeInfo().hasValue()) + if (printNameOnly || info.getClangTypeInfo().empty()) break; printCType(Ctx, Printer, info); break; @@ -4120,7 +4120,7 @@ class TypePrinter : public TypeVisitor { case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || !info.getClangTypeInfo().hasValue()) + if (printNameOnly || info.getClangTypeInfo().empty()) break; printCType(Ctx, Printer, info); break; From eead4ae8f05a91e2a087d027e341712d500f263b Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 18 Aug 2020 16:18:38 -0700 Subject: [PATCH 398/663] [NFC] Remove unused function parameter. --- include/swift/AST/ASTContext.h | 1 - lib/AST/ASTContext.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index e3ecfbb158dfb..7697baf4d1d01 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -606,7 +606,6 @@ class ASTContext final { const clang::Type * getCanonicalClangFunctionType( ArrayRef params, Optional result, - const SILFunctionType::ExtInfo incompleteExtInfo, SILFunctionType::Representation trueRep); /// Get the Swift declaration that a Clang declaration was exported from, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ce4f9c980bf6f..ca9d3ed0f34e8 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4477,7 +4477,6 @@ const clang::Type * ASTContext::getCanonicalClangFunctionType( ArrayRef params, Optional result, - SILFunctionType::ExtInfo incompleteExtInfo, SILFunctionType::Representation trueRep) { auto *ty = getClangTypeConverter().getFunctionType(params, result, trueRep); return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr; From eeec16f14322e96577e21a9e0d2b554fb98dd313 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Wed, 19 Aug 2020 18:06:00 -0700 Subject: [PATCH 399/663] [NFC] Remove redundant ExtInfo parameter for getBridgedFunctionType. At all call-sites, the extInfo passed as the third argument is computed directly from the second argument, so we compute it directly in getBridgedFunctionType. --- include/swift/SIL/TypeLowering.h | 1 - lib/SIL/IR/SILFunctionType.cpp | 13 ++++--------- lib/SIL/IR/TypeLowering.cpp | 2 +- lib/SILGen/SILGenApply.cpp | 1 - lib/SILGen/SILGenBridging.cpp | 3 +-- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index aba919ee0090c..344087f0a1aaf 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -992,7 +992,6 @@ class TypeConverter { /// Given a function type, yield its bridged formal type. CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern, CanAnyFunctionType fnType, - AnyFunctionType::ExtInfo extInfo, Bridgeability bridging); /// Given a referenced value and the substituted formal type of a diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 2d3e10054313d..794706f5c15b2 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -3984,7 +3984,6 @@ SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, CanAnyFunctionType TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, CanAnyFunctionType t, - AnyFunctionType::ExtInfo extInfo, Bridgeability bridging) { // Pull out the generic signature. CanGenericSignature genericSig = t.getOptGenericSignature(); @@ -3996,12 +3995,8 @@ TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, case SILFunctionTypeRepresentation::Closure: case SILFunctionTypeRepresentation::WitnessMethod: { // No bridging needed for native functions. - if (t->getExtInfo().isEqualTo(extInfo, useClangTypes(t))) - return t; - return CanAnyFunctionType::get(genericSig, t.getParams(), t.getResult(), - extInfo); + return t; } - case SILFunctionTypeRepresentation::CFunctionPointer: case SILFunctionTypeRepresentation::Block: case SILFunctionTypeRepresentation::ObjCMethod: { @@ -4016,7 +4011,7 @@ TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, suppressOptional); return CanAnyFunctionType::get(genericSig, llvm::makeArrayRef(params), - result, extInfo); + result, t->getExtInfo()); } } llvm_unreachable("bad calling convention"); @@ -4098,7 +4093,6 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, auto bridging = Bridgeability::Full; unsigned numParameterLists = constant.getParameterListCount(); - auto extInfo = fnType->getExtInfo(); // Form an abstraction pattern for bridging purposes. AbstractionPattern bridgingFnPattern = @@ -4108,12 +4102,13 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, // Fast path: no uncurrying required. if (numParameterLists == 1) { auto bridgedFnType = - getBridgedFunctionType(bridgingFnPattern, fnType, extInfo, bridging); + getBridgedFunctionType(bridgingFnPattern, fnType, bridging); bridgingFnPattern.rewriteType(bridgingFnPattern.getGenericSignature(), bridgedFnType); return { bridgingFnPattern, bridgedFnType }; } + auto extInfo = fnType->getExtInfo(); SILFunctionTypeRepresentation rep = extInfo.getSILRepresentation(); assert(rep != SILFunctionType::Representation::Block && "objc blocks cannot be curried"); diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index e1d4417e42dd6..45a725074cb8d 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -1964,7 +1964,7 @@ TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion, // Bridge the parameters and result of the function type. auto bridgedFnType = - TC.getBridgedFunctionType(origType, substFnType, extInfo, bridging); + TC.getBridgedFunctionType(origType, substFnType, bridging); substFnType = bridgedFnType; // Also rewrite the type of the abstraction pattern. diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index bffecc2c2c187..22d3136ca776c 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -76,7 +76,6 @@ getIndirectApplyAbstractionPattern(SILGenFunction &SGF, // bridged to a foreign type. auto bridgedType = SGF.SGM.Types.getBridgedFunctionType(pattern, fnType, - fnType->getExtInfo(), Bridgeability::Full); pattern.rewriteType(CanGenericSignature(), bridgedType); return pattern; diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 7eedc3b1975fa..0c1bb7d417a89 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -350,8 +350,7 @@ getParameterTypes(AnyFunctionType::CanParamArrayRef params) { static CanAnyFunctionType getBridgedBlockType(SILGenModule &SGM, CanAnyFunctionType blockType) { return SGM.Types.getBridgedFunctionType(AbstractionPattern(blockType), - blockType, blockType->getExtInfo(), - Bridgeability::Full); + blockType, Bridgeability::Full); } static void buildFuncToBlockInvokeBody(SILGenFunction &SGF, From fdbcd1236fd6d94239eb37b07cb729c4eae466aa Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 20 Aug 2020 17:11:48 -0700 Subject: [PATCH 400/663] [NFC] Bridge based on SILFunctionLanguage instead of Representation. --- lib/SIL/IR/SILFunctionType.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 794706f5c15b2..29a40a911d107 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -3988,18 +3988,13 @@ TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, // Pull out the generic signature. CanGenericSignature genericSig = t.getOptGenericSignature(); - switch (auto rep = t->getExtInfo().getSILRepresentation()) { - case SILFunctionTypeRepresentation::Thick: - case SILFunctionTypeRepresentation::Thin: - case SILFunctionTypeRepresentation::Method: - case SILFunctionTypeRepresentation::Closure: - case SILFunctionTypeRepresentation::WitnessMethod: { + auto rep = t->getExtInfo().getSILRepresentation(); + switch (getSILFunctionLanguage(rep)) { + case SILFunctionLanguage::Swift: { // No bridging needed for native functions. return t; } - case SILFunctionTypeRepresentation::CFunctionPointer: - case SILFunctionTypeRepresentation::Block: - case SILFunctionTypeRepresentation::ObjCMethod: { + case SILFunctionLanguage::C: { SmallVector params; getBridgedParams(rep, pattern, t->getParams(), params, bridging); From f86aad9b294819a84aa1493330e07b0675ac90e6 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 20 Aug 2020 18:00:27 -0700 Subject: [PATCH 401/663] [NFC] Extract computation of SILExtInfoBuilder bits into new method. --- include/swift/AST/ExtInfo.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 6b2bc1b8bf7c5..0850870f6ce45 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -505,6 +505,15 @@ class SILExtInfoBuilder { SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo) : bits(bits), clangTypeInfo(clangTypeInfo) {} + static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric, + bool isNoEscape, bool isAsync, + DifferentiabilityKind diffKind) { + return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) | + (isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) | + (((unsigned)diffKind << DifferentiabilityMaskOffset) & + DifferentiabilityMask); + } + public: // Constructor with all defaults. SILExtInfoBuilder() : bits(0), clangTypeInfo(ClangTypeInfo(nullptr)) {} @@ -513,12 +522,9 @@ class SILExtInfoBuilder { SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape, bool isAsync, DifferentiabilityKind diffKind, const clang::Type *type) - : SILExtInfoBuilder( - ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) | - (isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) | - (((unsigned)diffKind << DifferentiabilityMaskOffset) & - DifferentiabilityMask), - ClangTypeInfo(type)) {} + : SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isAsync, + diffKind), + ClangTypeInfo(type)) {} void checkInvariants() const; From c4ad840ad3dbc40c885af117105a3a92326df149 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Thu, 20 Aug 2020 17:40:41 -0700 Subject: [PATCH 402/663] [NFC] Reuse SILExtInfoBuilder's main constructor in default constructor. --- include/swift/AST/ExtInfo.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 0850870f6ce45..55ea27bc47dc8 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -516,7 +516,7 @@ class SILExtInfoBuilder { public: // Constructor with all defaults. - SILExtInfoBuilder() : bits(0), clangTypeInfo(ClangTypeInfo(nullptr)) {} + SILExtInfoBuilder() : SILExtInfoBuilder(0, ClangTypeInfo(nullptr)) {} // Constructor for polymorphic type. SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape, @@ -526,6 +526,12 @@ class SILExtInfoBuilder { diffKind), ClangTypeInfo(type)) {} + SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric) + : SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric, + info.isNoEscape(), info.isAsync(), + info.getDifferentiabilityKind()), + info.getClangTypeInfo()) {} + void checkInvariants() const; /// Check if \c this is well-formed and create an ExtInfo. From 863bca87e8644151d492f5c526fe62d4fee8ef9f Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 27 Aug 2020 12:57:30 -0700 Subject: [PATCH 403/663] [Dependency Scanner] Prefix Clang dependency scanner search path arguments with `-Xcc` Experimentally, this seems to be required for these paths to actually be picked up by the underlying scanner. --- lib/ClangImporter/ClangModuleDependencyScanner.cpp | 6 ++---- test/ScanDependencies/batch_module_scan.swift | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index 290dd69506ed2..82c502b962ff0 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -260,12 +260,10 @@ void ClangImporter::recordModuleDependencies( // be found via search paths. Passing these headers as explicit inputs can // be quite challenging. for (auto &path: Impl.SwiftContext.SearchPathOpts.ImportSearchPaths) { - swiftArgs.push_back("-I"); - swiftArgs.push_back(path); + addClangArg("-I" + path); } for (auto &path: Impl.SwiftContext.SearchPathOpts.FrameworkSearchPaths) { - swiftArgs.push_back(path.IsSystem ? "-Fsystem": "-F"); - swiftArgs.push_back(path.Path); + addClangArg((path.IsSystem ? "-Fsystem": "-F") + path.Path); } // Swift frontend option for input file path (Foo.modulemap). diff --git a/test/ScanDependencies/batch_module_scan.swift b/test/ScanDependencies/batch_module_scan.swift index 4f0c173f7a99f..59189771b340f 100644 --- a/test/ScanDependencies/batch_module_scan.swift +++ b/test/ScanDependencies/batch_module_scan.swift @@ -28,7 +28,7 @@ // CHECK-PCM-NEXT: }, // CHECK-PCM-NEXT: { // CHECK-PCM-NEXT: "modulePath": "F.pcm", -// CHECK-PCM: "-I" +// CHECK-PCM: "-I // CHECK-SWIFT: { // CHECK-SWIFT-NEXT: "mainModuleName": "F", From 4847ec9a6bed06259750b7595871e87678acd554 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 27 Aug 2020 13:18:45 -0700 Subject: [PATCH 404/663] [AST/TypeChecker] Add more asserts to make sure types don't get into AST --- lib/AST/ASTContext.cpp | 2 ++ lib/AST/Expr.cpp | 4 ++-- lib/AST/SILLayout.cpp | 2 ++ lib/AST/Type.cpp | 2 +- lib/AST/TypeCheckRequests.cpp | 1 + lib/Sema/CSApply.cpp | 2 ++ lib/Sema/CSDiagnostics.cpp | 2 ++ lib/Sema/CSGen.cpp | 1 + lib/Sema/TypeCheckCodeCompletion.cpp | 2 ++ 9 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8a744f7d03d94..b33d17cbd0636 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2811,6 +2811,7 @@ ReferenceStorageType *ReferenceStorageType::get(Type T, ReferenceOwnership ownership, const ASTContext &C) { assert(!T->hasTypeVariable()); // not meaningful in type-checker + assert(!T->hasHole()); switch (optionalityOf(ownership)) { case ReferenceOwnershipOptionality::Disallowed: assert(!T->getOptionalObjectType() && "optional type is disallowed"); @@ -3197,6 +3198,7 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig, ExtInfo info) { assert(sig && "no generic signature for generic function type?!"); assert(!result->hasTypeVariable()); + assert(!result->hasHole()); llvm::FoldingSetNodeID id; GenericFunctionType::Profile(id, sig, params, result, info); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 95a290a0d303c..40e632b5a09ca 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -126,7 +126,7 @@ namespace { } // end anonymous namespace void Expr::setType(Type T) { - assert(!T || !T->hasTypeVariable()); + assert(!T || !T->hasTypeVariable() || !T->hasHole()); Ty = T; } @@ -2001,7 +2001,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const { } void ClosureExpr::setExplicitResultType(Type ty) { - assert(ty && !ty->hasTypeVariable()); + assert(ty && !ty->hasTypeVariable() && !ty->hasHole()); ExplicitResultTypeAndBodyState.getPointer() ->setType(MetatypeType::get(ty)); } diff --git a/lib/AST/SILLayout.cpp b/lib/AST/SILLayout.cpp index da70ccd300917..ffbd35175d226 100644 --- a/lib/AST/SILLayout.cpp +++ b/lib/AST/SILLayout.cpp @@ -52,6 +52,8 @@ static void verifyFields(CanGenericSignature Sig, ArrayRef Fields) { && "SILLayout field cannot have an archetype type"); assert(!ty->hasTypeVariable() && "SILLayout cannot contain constraint system type variables"); + assert(!ty->hasHole() && + "SILLayout cannot contain constraint system type holes"); if (!ty->hasTypeParameter()) continue; field.getLoweredType().findIf([Sig](Type t) -> bool { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 6cc2cc05a01fd..d91dc2b1a8fd8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -76,7 +76,7 @@ Type QuerySubstitutionMap::operator()(SubstitutableType *type) const { } void TypeLoc::setType(Type Ty) { - assert(!Ty || !Ty->hasTypeVariable()); + assert(!Ty || !Ty->hasTypeVariable() || !Ty->hasHole()); this->Ty = Ty; } diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 82419b737dfb5..b6bf4130e16f3 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -1013,6 +1013,7 @@ void InterfaceTypeRequest::cacheResult(Type type) const { auto *decl = std::get<0>(getStorage()); if (type) { assert(!type->hasTypeVariable() && "Type variable in interface type"); + assert(!type->hasHole() && "Type hole in interface type"); assert(!type->is() && "Interface type must be materializable"); assert(!type->hasArchetype() && "Archetype in interface type"); } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index b4ec32888c67c..b86a7919376ec 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7673,6 +7673,8 @@ namespace { componentType = solution.simplifyType(cs.getType(kp, i)); assert(!componentType->hasTypeVariable() && "Should not write type variable into key-path component"); + assert(!componentType->hasHole() && + "Should not write type hole into key-path component"); kp->getMutableComponents()[i].setComponentType(componentType); } } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 25b54e13e7538..97ecb96e50aa9 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1235,8 +1235,10 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { assert(!baseType->hasTypeVariable() && "Base type must not be a type variable"); + assert(!baseType->isHole() && "Base type must not be a type hole"); assert(!unwrappedType->hasTypeVariable() && "Unwrapped type must not be a type variable"); + assert(!unwrappedType->isHole() && "Unwrapped type must not be a type hole"); if (!baseType->getOptionalObjectType()) return false; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index d54105b2c721a..38f0861ed1c91 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3684,6 +3684,7 @@ namespace { if (CG.getConstraintSystem().shouldReusePrecheckedType()) { if (expr->getType()) { assert(!expr->getType()->hasTypeVariable()); + assert(!expr->getType()->hasHole()); CG.getConstraintSystem().cacheType(expr); return { false, expr }; } diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index 77a8222774652..6ba92aeb42dd4 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -416,6 +416,8 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, assert(exprType && !exprType->hasTypeVariable() && "free type variable with FreeTypeVariableBinding::GenericParameters?"); + assert(exprType && !exprType->hasHole() && + "type hole with FreeTypeVariableBinding::GenericParameters?"); if (exprType->hasError()) { recoverOriginalType(); From 0bef4a661bdf7c64d4145fb76a852b238381b4ff Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 27 Aug 2020 11:08:52 -0700 Subject: [PATCH 405/663] Give global once symbols stabler manglings. This allows symbol ordering and other analyses to be more robust with regards to these symbols. --- docs/ABI/Mangling.rst | 5 +++ include/swift/AST/ASTMangler.h | 3 +- include/swift/Demangling/DemangleNodes.def | 3 ++ lib/AST/ASTMangler.cpp | 36 +++++++++++-------- lib/Demangling/Demangler.cpp | 26 +++++++++++++- lib/Demangling/NodePrinter.cpp | 25 +++++++++++++ lib/Demangling/OldRemangler.cpp | 9 +++++ lib/Demangling/Remangler.cpp | 17 +++++++++ lib/SILGen/SILGenGlobalVariable.cpp | 16 ++------- test/IRGen/big_types_corner_cases_tiny.swift | 2 +- test/IRGen/globals.swift | 3 +- test/IRGen/lazy_globals.swift | 10 +++--- test/SILGen/default_arguments.swift | 2 +- test/SILGen/fragile_globals.swift | 6 ++-- test/SILGen/global_resilience.swift | 8 ++--- test/SILGen/lazy_globals.swift | 24 ++++++------- test/SILGen/lazy_globals_multiple_vars.swift | 12 +++---- test/SILGen/observers.swift | 2 +- test/SILOptimizer/access_marker_verify.swift | 12 +++---- .../access_marker_verify_objc.swift | 4 +-- test/SILOptimizer/inline_addressor.swift | 4 +-- .../SILOptimizer/large_string_array.swift.gyb | 2 +- 22 files changed, 155 insertions(+), 76 deletions(-) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index f35339c9ebb70..9e60d04a4f5e3 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -176,6 +176,11 @@ Globals global ::= global 'MJ' // noncanonical specialized generic type metadata instantiation cache associated with global global ::= global 'MN' // noncanonical specialized generic type metadata for global + #if SWIFT_RUNTIME_VERSION >= 5.4 + global ::= context (decl-name '_')+ 'WZ' // global variable one-time initialization function + global ::= context (decl-name '_')+ 'Wz' // global variable one-time initialization token + #endif + A direct symbol resolves directly to the address of an object. An indirect symbol resolves to the address of a pointer to the object. They are distinct manglings to make a certain class of bugs diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 50c401e7ee2bc..b244e766ffc52 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -146,7 +146,8 @@ class ASTMangler : public Mangler { std::string mangleGlobalVariableFull(const VarDecl *decl); - std::string mangleGlobalInit(const VarDecl *decl, int counter, + std::string mangleGlobalInit(const PatternBindingDecl *decl, + unsigned entry, bool isInitFunc); std::string mangleReabstractionThunkHelper(CanSILFunctionType ThunkType, diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 468a0711f90f4..1c3c612f9e98a 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -294,6 +294,9 @@ NODE(CanonicalSpecializedGenericTypeMetadataAccessFunction) NODE(MetadataInstantiationCache) NODE(NoncanonicalSpecializedGenericTypeMetadata) NODE(NoncanonicalSpecializedGenericTypeMetadataCache) +NODE(GlobalVariableOnceFunction) +NODE(GlobalVariableOnceToken) +NODE(GlobalVariableOnceDeclList) #undef CONTEXT_NODE #undef NODE diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index be1c4af4e0ea1..ee1269258f4f2 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -336,21 +336,29 @@ std::string ASTMangler::mangleKeyPathHashHelper(ArrayRef indices, return finalize(); } -std::string ASTMangler::mangleGlobalInit(const VarDecl *decl, int counter, +std::string ASTMangler::mangleGlobalInit(const PatternBindingDecl *pd, + unsigned pbdEntry, bool isInitFunc) { - auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); - auto fileUnit = cast(topLevelContext); - Identifier discriminator = fileUnit->getDiscriminatorForPrivateValue(decl); - assert(!discriminator.empty()); - assert(!isNonAscii(discriminator.str()) && - "discriminator contains non-ASCII characters"); - assert(!clang::isDigit(discriminator.str().front()) && - "not a valid identifier"); - - Buffer << "globalinit_"; - appendIdentifier(discriminator.str()); - Buffer << (isInitFunc ? "_func" : "_token"); - Buffer << counter; + beginMangling(); + + Pattern *pattern = pd->getPattern(pbdEntry); + bool first = true; + pattern->forEachVariable([&](VarDecl *D) { + if (first) { + appendContextOf(D); + first = false; + } + appendDeclName(D); + appendListSeparator(); + }); + assert(!first && "no variables in pattern binding?!"); + + if (isInitFunc) { + appendOperator("WZ"); + } else { + appendOperator("Wz"); + } + return finalize(); } diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 3628481d8a47e..f49ba90261714 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2669,7 +2669,7 @@ NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind) { } NodePointer Demangler::demangleWitness() { - switch (nextChar()) { + switch (char c = nextChar()) { case 'C': return createWithChild(Node::Kind::EnumCase, popNode(isEntity)); @@ -2811,6 +2811,30 @@ NodePointer Demangler::demangleWitness() { return nullptr; } } + case 'Z': + case 'z': { + auto declList = createNode(Node::Kind::GlobalVariableOnceDeclList); + std::vector vars; + while (auto sig = popNode(Node::Kind::FirstElementMarker)) { + auto identifier = popNode(isDeclName); + if (!identifier) + return nullptr; + vars.push_back(identifier); + } + for (auto i = vars.rbegin(); i != vars.rend(); ++i) { + declList->addChild(*i, *this); + } + + auto context = popContext(); + if (!context) + return nullptr; + Node::Kind kind = c == 'Z' + ? Node::Kind::GlobalVariableOnceFunction + : Node::Kind::GlobalVariableOnceToken; + return createWithChildren(kind, + context, + declList); + } default: return nullptr; } diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index e7ea0e52e29d6..3a7fc824699b2 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -552,6 +552,9 @@ class NodePrinter { case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadata: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache: + case Node::Kind::GlobalVariableOnceDeclList: + case Node::Kind::GlobalVariableOnceFunction: + case Node::Kind::GlobalVariableOnceToken: return false; } printer_unreachable("bad node kind"); @@ -2466,6 +2469,28 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { Printer << "cache variable for noncanonical specialized generic type metadata for "; print(Node->getChild(0)); return nullptr; + case Node::Kind::GlobalVariableOnceToken: + case Node::Kind::GlobalVariableOnceFunction: + Printer << (kind == Node::Kind::GlobalVariableOnceToken + ? "one-time initialization token for " + : "one-time initialization function for "); + printContext(Node->getChild(0)); + print(Node->getChild(1)); + return nullptr; + case Node::Kind::GlobalVariableOnceDeclList: + if (Node->getNumChildren() == 1) { + print(Node->getChild(0)); + } else { + Printer << '('; + for (unsigned i = 0, e = Node->getNumChildren(); i < e; ++i) { + if (i != 0) { + Printer << ", "; + } + print(Node->getChild(i)); + } + Printer << ')'; + } + return nullptr; } printer_unreachable("bad node kind!"); } diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index ba7ca2eb51960..7df26cbfad047 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -2139,6 +2139,15 @@ void Remangler::mangleAccessorFunctionReference(Node *node) { void Remangler::mangleMetadataInstantiationCache(Node *node) { unreachable("unsupported"); } +void Remangler::mangleGlobalVariableOnceToken(Node *node) { + unreachable("unsupported"); +} +void Remangler::mangleGlobalVariableOnceFunction(Node *node) { + unreachable("unsupported"); +} +void Remangler::mangleGlobalVariableOnceDeclList(Node *node) { + unreachable("unsupported"); +} void Remangler::mangleCanonicalSpecializedGenericMetaclass(Node *node) { Buffer << "MM"; diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 60dfeafaee925..8abad3f38cf0f 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2566,6 +2566,23 @@ void Remangler::mangleNoncanonicalSpecializedGenericTypeMetadataCache(Node *node Buffer << "MJ"; } +void Remangler::mangleGlobalVariableOnceToken(Node *node) { + mangleChildNodes(node); + Buffer << "Wz"; +} + +void Remangler::mangleGlobalVariableOnceFunction(Node *node) { + mangleChildNodes(node); + Buffer << "WZ"; +} + +void Remangler::mangleGlobalVariableOnceDeclList(Node *node) { + for (unsigned i = 0, e = node->getNumChildren(); i < e; ++i) { + mangle(node->getChild(i)); + Buffer << '_'; + } +} + } // anonymous namespace /// The top-level interface to the remangler. diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 551b438f461f0..a43ce63f99508 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -178,20 +178,8 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, ->areAllParamsConcrete()); } - // Emit the lazy initialization token for the initialization expression. - auto counter = anonymousSymbolCounter++; - - // Pick one variable of the pattern. Usually it's only one variable, but it - // can also be something like: var (a, b) = ... - Pattern *pattern = pd->getPattern(pbdEntry); - VarDecl *varDecl = nullptr; - pattern->forEachVariable([&](VarDecl *D) { - varDecl = D; - }); - assert(varDecl); - Mangle::ASTMangler TokenMangler; - std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(varDecl, counter, + std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(pd, pbdEntry, false); auto onceTy = BuiltinIntegerType::getWordType(M.getASTContext()); @@ -207,7 +195,7 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, // Emit the initialization code into a function. Mangle::ASTMangler FuncMangler; - std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(varDecl, counter, + std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(pd, pbdEntry, true); SILFunction *onceFunc = emitLazyGlobalInitializer(onceFuncBuffer, pd, diff --git a/test/IRGen/big_types_corner_cases_tiny.swift b/test/IRGen/big_types_corner_cases_tiny.swift index 8a9a88b28f9b1..a4fb5a9a6929a 100644 --- a/test/IRGen/big_types_corner_cases_tiny.swift +++ b/test/IRGen/big_types_corner_cases_tiny.swift @@ -4,7 +4,7 @@ // DO NOT ADD ANY MORE CODE TO THIS FILE! -// CHECK-LABEL: define internal void @globalinit +// CHECK-LABEL: define internal void @{{.*}}WZ // CHECK: [[ALLOC:%.*]] = alloca %T27big_types_corner_cases_tiny30LoadableStructWithBiggerStringV // CHECK: call swiftcc void {{.*}}(%T27big_types_corner_cases_tiny30LoadableStructWithBiggerStringV* noalias nocapture sret [[ALLOC]] let model = ClassWithLoadableStructWithBiggerString().f() diff --git a/test/IRGen/globals.swift b/test/IRGen/globals.swift index 509922e9483ed..b423befb38b6d 100644 --- a/test/IRGen/globals.swift +++ b/test/IRGen/globals.swift @@ -53,6 +53,5 @@ extension A { // CHECK: define{{( dllexport)?}}{{( protected)?}} i32 @main(i32 %0, i8** %1) {{.*}} { // CHECK: store i64 {{.*}}, i64* getelementptr inbounds ([[INT]], [[INT]]* @"$s7globals2g0Sivp", i32 0, i32 0), align 8 -// FIXME: give these initializers a real mangled name -// CHECK: define internal void @globalinit_{{.*}}func0() {{.*}} { +// CHECK: define internal void @"{{.*}}WZ"() {{.*}} { // CHECK: store i64 5, i64* getelementptr inbounds (%TSi, %TSi* @"$s7globals1AV3fooSivpZ", i32 0, i32 0), align 8 diff --git a/test/IRGen/lazy_globals.swift b/test/IRGen/lazy_globals.swift index ce0f387d9e485..8b1d761c70e40 100644 --- a/test/IRGen/lazy_globals.swift +++ b/test/IRGen/lazy_globals.swift @@ -2,12 +2,12 @@ // REQUIRES: CPU=x86_64 -// CHECK: @globalinit_[[T:.*]]_token0 = internal global i64 0, align 8 +// CHECK: @"[[T:.*]]Wz" = internal global i64 0, align 8 // CHECK: @"$s12lazy_globals1xSivp" = hidden global %TSi zeroinitializer, align 8 // CHECK: @"$s12lazy_globals1ySivp" = hidden global %TSi zeroinitializer, align 8 // CHECK: @"$s12lazy_globals1zSivp" = hidden global %TSi zeroinitializer, align 8 -// CHECK: define internal void @globalinit_[[T]]_func0() {{.*}} { +// CHECK: define internal void @"[[T]]WZ"() {{.*}} { // CHECK: entry: // CHECK: store i64 1, i64* getelementptr inbounds (%TSi, %TSi* @"$s12lazy_globals1xSivp", i32 0, i32 0), align 8 // CHECK: store i64 2, i64* getelementptr inbounds (%TSi, %TSi* @"$s12lazy_globals1ySivp", i32 0, i32 0), align 8 @@ -17,17 +17,17 @@ // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1xSivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1ySivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1zSivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } var (x, y, z) = (1, 2, 3) diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift index 94450cf10b7a9..0895a9a0f018a 100644 --- a/test/SILGen/default_arguments.swift +++ b/test/SILGen/default_arguments.swift @@ -156,7 +156,7 @@ class Foo { return x } - // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_33_E52D764B1F2009F2390B2B8DF62DAEB8_func0 + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ // CHECK: string_literal utf8 "Foo" static let x = Foo(int:0) diff --git a/test/SILGen/fragile_globals.swift b/test/SILGen/fragile_globals.swift index 0a4ace7ffa3a1..c6c6e412eece0 100644 --- a/test/SILGen/fragile_globals.swift +++ b/test/SILGen/fragile_globals.swift @@ -11,7 +11,7 @@ var mygg = 29 // Check if we have one token: from mygg. // Initializers from other modules are never fragile. -// CHECK: sil_global private{{.*}} @globalinit_[[T3:.*]]_token0 +// CHECK: sil_global private{{.*}} @[[T3:.*]]Wz //@inlinable public func sum() -> Int { @@ -21,8 +21,8 @@ public func sum() -> Int { // Check if all the addressors are inlined. // CHECK-LABEL: sil {{.*}}@$s15fragile_globals3sumSiyF -// CHECK-DAG: global_addr @globalinit_[[T1:.*]]_token0 -// CHECK-DAG: function_ref @globalinit_[[T1]]_func0 +// CHECK-DAG: global_addr @[[T1:.*]]Wz +// CHECK-DAG: function_ref @[[T1]]WZ // CHECK-DAG: global_addr @$s15fragile_globals4myggSivp // CHECK-DAG: function_ref @$s7ModuleA2ggSivau // CHECK-DAG: function_ref @$s7ModuleB2ggSivau diff --git a/test/SILGen/global_resilience.swift b/test/SILGen/global_resilience.swift index ee01a547e3b4e..2f5ea45c549e8 100644 --- a/test/SILGen/global_resilience.swift +++ b/test/SILGen/global_resilience.swift @@ -43,21 +43,21 @@ public var myEmptyGlobal = MyEmptyStruct() // Mutable addressor for fixed-layout global -// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_{{.*}}_func1 +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ // CHECK: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return // CHECK-LABEL: sil [global_init] [ossa] @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvau -// CHECK: function_ref @globalinit_{{.*}}_func1 +// CHECK: function_ref @{{.*}}WZ // CHECK: global_addr @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return -// CHECK-OPT-LABEL: sil private [global_init_once_fn] @globalinit_{{.*}}_func1 +// CHECK-OPT-LABEL: sil private [global_init_once_fn] @{{.*}}WZ // CHECK-OPT: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK-OPT: return // CHECK-OPT-LABEL: sil [global_init] @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvau -// CHECK-OPT: function_ref @globalinit_{{.*}}_func1 +// CHECK-OPT: function_ref @{{.*}}WZ // CHECK-OPT: global_addr @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvp // CHECK-OPT: return diff --git a/test/SILGen/lazy_globals.swift b/test/SILGen/lazy_globals.swift index c772aa7a2bd27..c5604dc5a159a 100644 --- a/test/SILGen/lazy_globals.swift +++ b/test/SILGen/lazy_globals.swift @@ -1,14 +1,14 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T:.*]]_func0 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals1xSiv // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals1xSivp : $*Int // CHECK: store {{%.*}} to [trivial] [[XADDR]] : $*Int // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals1xSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token0 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func0 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals1xSivp : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -16,7 +16,7 @@ // CHECK: } var x: Int = 0 -// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T:.*]]_func1 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3FooV3fooSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3FooV3fooSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -24,9 +24,9 @@ var x: Int = 0 struct Foo { // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals3FooV3fooSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token1 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func1 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals3FooV3fooSivpZ : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -40,7 +40,7 @@ struct Foo { static var initialized: Int = 57 } -// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T:.*]]_func3 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*3bar.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3BarO3barSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3BarO3barSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -48,9 +48,9 @@ struct Foo { enum Bar { // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals3BarO3barSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token3 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func3 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals3BarO3barSivpZ : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -63,13 +63,13 @@ enum Bar { func f() -> (Int, Int) { return (1, 2) } -// CHECK: sil private [global_init_once_fn] [ossa] @globalinit_[[T]]_func4 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*2a1.*2b1.*]]WZ : $@convention(c) () -> () { // CHECK: function_ref @$s12lazy_globals1fSi_SityF : $@convention(thin) () -> (Int, Int) // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals2a1Sivau : $@convention(thin) () -> Builtin.RawPointer -// CHECK: function_ref @globalinit_[[T]]_func4 : $@convention(c) () -> () +// CHECK: function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: global_addr @$s12lazy_globals2a1Sivp : $*Int // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals2b1Sivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: function_ref @globalinit_[[T]]_func4 : $@convention(c) () -> () +// CHECK: function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: global_addr @$s12lazy_globals2b1Sivp : $*Int var (a1, b1) = f() diff --git a/test/SILGen/lazy_globals_multiple_vars.swift b/test/SILGen/lazy_globals_multiple_vars.swift index bad5e0b41e1cc..059cfa8267cbf 100644 --- a/test/SILGen/lazy_globals_multiple_vars.swift +++ b/test/SILGen/lazy_globals_multiple_vars.swift @@ -1,34 +1,34 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_A_B:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_A_B:@.*1a.*1b.*WZ]] : // CHECK: alloc_global @$s26lazy_globals_multiple_vars1aSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1aSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1bSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1bSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1aSivau -// CHECK: global_addr [[TOKEN_A_B:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_A_B:@.*1a.*1b.*Wz]] : // CHECK: function_ref [[INIT_A_B]] // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1bSivau // CHECK: global_addr [[TOKEN_A_B]] // CHECK: function_ref [[INIT_A_B]] var (a, b) = (1, 2) -// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_C:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_C:@.*1c.*WZ]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1cSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1cSivau -// CHECK: global_addr [[TOKEN_C:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_C:@.*1c.*Wz]] : // CHECK: function_ref [[INIT_C]] -// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_D:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_D:@.*1d.*WZ]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1dSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1dSivau // CHECK-NOT: global_addr [[TOKEN_C]] -// CHECK: global_addr [[TOKEN_D:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_D:@.*1d.*Wz]] : // CHECK-NOT: global_addr [[TOKEN_C]] // CHECK: function_ref [[INIT_D]] var c = 1, d = 2 diff --git a/test/SILGen/observers.swift b/test/SILGen/observers.swift index 22ac63b2a603e..6b6c6d4503fa1 100644 --- a/test/SILGen/observers.swift +++ b/test/SILGen/observers.swift @@ -171,7 +171,7 @@ public struct DidSetWillSetTests { var global_observing_property : Int = zero { // The variable is initialized with "zero". - // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_{{.*}}_func1 : $@convention(c) () -> () { + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: bb0: // CHECK-NEXT: alloc_global @$s9observers25global_observing_propertySiv // CHECK-NEXT: %1 = global_addr @$s9observers25global_observing_propertySivp : $*Int diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift index af14c54be2fcf..6062f4116579f 100644 --- a/test/SILOptimizer/access_marker_verify.swift +++ b/test/SILOptimizer/access_marker_verify.swift @@ -627,17 +627,17 @@ func testShims() -> UInt32 { // --- global variable initialization. var globalString1 = "⓪" // start non-empty -// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_33_{{.*}}_func0 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString1SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString1SSvp : $*String // CHECK: apply // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[GA]] : $*String // CHECK: store %{{.*}} to [init] [[ACCESS]] : $*String // CHECK: end_access -// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func0' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' var globalString2 = globalString1 -// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString2SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString2SSvp : $*String // CHECK: apply @@ -648,7 +648,7 @@ var globalString2 = globalString1 // CHECK: end_access [[INIT]] : $*String // CHECK: end_access [[ACCESS]] : $*String // CHECK-NOT: end_access -// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' // --- getter. @@ -1037,13 +1037,13 @@ func testPointerInit(x: Int, y: UnsafeMutablePointer) { class testInitExistentialGlobal { static var testProperty: P = StructP() } -// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit{{.*}} : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ // CHECK: [[GADR:%.*]] = global_addr @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ : $*P // CHECK: %{{.*}} = apply %{{.*}}({{.*}}) : $@convention(method) (@thin StructP.Type) -> StructP // CHECK: [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP // CHECK: store %{{.*}} to [trivial] [[EADR]] : $*StructP -// CHECK-LABEL: } // end sil function 'globalinit +// CHECK-LABEL: } // end sil function '{{.*}}WZ public enum SomeError: Swift.Error { case error diff --git a/test/SILOptimizer/access_marker_verify_objc.swift b/test/SILOptimizer/access_marker_verify_objc.swift index b9fc5fbaa7c0e..c3e1ed48efe35 100644 --- a/test/SILOptimizer/access_marker_verify_objc.swift +++ b/test/SILOptimizer/access_marker_verify_objc.swift @@ -12,14 +12,14 @@ import Foundation // --- initializer `let` of CFString. // The verifier should ignore this. -// CHECK_LABEL: sil private @globalinit{{.*}} : $@convention(c) () -> () { +// CHECK_LABEL: sil private @{{.*}}WZ : $@convention(c) () -> () { // CHECK: bb0: // CHECK: alloc_global @$s25access_marker_verify_objc12testCFStringC8cfStringSo0F3RefavpZ // CHECK: [[GA:%.*]] = global_addr @$s25access_marker_verify_objc12testCFStringC8cfStringSo0F3RefavpZ : $*CFString // CHECK-NOT: begin_access // CHECK: store %{{.*}} to [init] [[GA]] : $*CFString // CHECK: return %{{.*}} : $() -// CHECK-LABEL: } // end sil function 'globalinit{{.*}}' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' class testCFString { public static let cfString: CFString = "" as CFString } diff --git a/test/SILOptimizer/inline_addressor.swift b/test/SILOptimizer/inline_addressor.swift index c78e0a25c5f41..369799a725370 100644 --- a/test/SILOptimizer/inline_addressor.swift +++ b/test/SILOptimizer/inline_addressor.swift @@ -11,10 +11,10 @@ var totalsum = nonTrivialInit(true) //CHECK-LABEL: sil {{.*}}testit //CHECK: {{^bb0}} -//CHECK: globalinit_ +//CHECK: WZ //CHECK-NOT: {{^bb0}} //CHECK: {{^bb1}} -//CHECK-NOT: globalinit +//CHECK-NOT: WZ //CHECK-NOT: totalsum //CHECK-NOT: inputval //CHECK: {{^}$}} diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 6285e4b97c75b..6b6093f78552b 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -15,7 +15,7 @@ // Check if the optimizer can optimize the whole array into a statically // initialized global -// CHECK: sil_global private @globalinit_{{.*}} : $_ContiguousArrayStorage = { +// CHECK: sil_global private @{{.*9str_array.*}}WZTv_ : $_ContiguousArrayStorage = { // CHECK: %initval = object $_ContiguousArrayStorage public let str_array: [String] = [ From 4b921c3487d3804c14718c374242619ff44c65fd Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sun, 23 Aug 2020 16:10:32 -0300 Subject: [PATCH 406/663] [Sema] Improve diagnostics for key path root type inferred as option accessing wrapped member --- include/swift/AST/DiagnosticsSema.def | 9 +++++++++ lib/Sema/CSDiagnostics.cpp | 16 +++++++++++++--- localization/diagnostics/en.yaml | 9 +++++++++ test/expr/unary/keypath/keypath.swift | 9 ++++++--- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index beaf7b6ea3dd5..90bc5604344ae 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1082,6 +1082,9 @@ NOTE(unwrap_with_guard,none, ERROR(optional_base_not_unwrapped,none, "value of optional type %0 must be unwrapped to refer to member %1 of " "wrapped base type %2", (Type, DeclNameRef, Type)) +ERROR(invalid_optional_infered_keypath_root, none, + "key path root inferred as optional type %0 must be unwrapped to refer to member %1 " + "of unwrapped type %2", (Type, DeclNameRef, Type)) NOTE(optional_base_chain,none, "chain the optional using '?' to access member %0 only for non-'nil' " "base values", (DeclNameRef)) @@ -1089,6 +1092,12 @@ NOTE(optional_base_remove_optional_for_keypath_root, none, "use unwrapped type %0 as key path root", (Type)) NOTE(optional_keypath_application_base, none, "use '?' to access key path subscript only for non-'nil' base values", ()) +NOTE(optional_key_path_root_base_chain, none, + "chain the optional using '?.' to access unwrapped type member %0", + (DeclNameRef)) +NOTE(optional_key_path_root_base_unwrap, none, + "unwrap the optional using '!.' to access unwrapped type member %0", + (DeclNameRef)) ERROR(missing_unwrap_optional_try,none, "value of optional type %0 not unwrapped; did you mean to use 'try!' " diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 4bef05bd9c4eb..ed980fef21cb6 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1071,9 +1071,6 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() { return false; auto sourceRange = getSourceRange(); - - emitDiagnostic(diag::optional_base_not_unwrapped, - baseType, Member, unwrappedBaseType); auto componentPathElt = locator->getLastElementAs(); @@ -1082,12 +1079,25 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() { // let's emit a tailored note suggesting to use its unwrapped type. auto *keyPathExpr = castToExpr(getAnchor()); if (auto rootType = keyPathExpr->getRootType()) { + emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member, + unwrappedBaseType); + emitDiagnostic(diag::optional_base_remove_optional_for_keypath_root, unwrappedBaseType) .fixItReplace(rootType->getSourceRange(), unwrappedBaseType.getString()); + } else { + emitDiagnostic(diag::invalid_optional_infered_keypath_root, baseType, + Member, unwrappedBaseType); + emitDiagnostic(diag::optional_key_path_root_base_chain, Member) + .fixItInsert(sourceRange.End, "?."); + emitDiagnostic(diag::optional_key_path_root_base_unwrap, Member) + .fixItInsert(sourceRange.End, "!."); } } else { + emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member, + unwrappedBaseType); + // FIXME: It would be nice to immediately offer "base?.member ?? defaultValue" // for non-optional results where that would be appropriate. For the moment // always offering "?" means that if the user chooses chaining, we'll end up diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index b346b96b115cc..0adbcc174f476 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -3136,6 +3136,9 @@ - id: optional_base_not_unwrapped msg: "value of optional type %0 must be unwrapped to refer to member %1 of wrapped base type %2" +- id: invalid_optional_infered_keypath_root + msg: "key path root inferred as optional type %0 must be unwrapped to refer to member %1 of unwrapped type %2" + - id: optional_base_chain msg: "chain the optional using '?' to access member %0 only for non-'nil' base values" @@ -3145,6 +3148,12 @@ - id: optional_keypath_application_base msg: "use '?' to access key path subscript only for non-'nil' base values" +- id: optional_key_path_root_base_chain + msg: "chain the optional using '?.' to access unwrapped type member %0" + +- id: optional_key_path_root_base_unwrap + msg: "unwrap the optional using '!.' to access unwrapped type member %0" + - id: missing_unwrap_optional_try msg: "value of optional type %0 not unwrapped; did you mean to use 'try!' or chain with '?'?" diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index 9b0333b0c0de4..326e148b5b6a7 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -1006,9 +1006,12 @@ func testMemberAccessOnOptionalKeyPathComponent() { // expected-error@-1 {{value of optional type '(Int, Int)?' must be unwrapped to refer to member '0' of wrapped base type '(Int, Int)'}} // expected-note@-2 {{use unwrapped type '(Int, Int)' as key path root}}{{4-15=(Int, Int)}} - // TODO(diagnostics) Improve diagnostics refering to key path root not able to be infered as an optional type. - SR5688_KP(\.count) - // expected-error@-1 {{value of optional type 'String?' must be unwrapped to refer to member 'count' of wrapped base type 'String'}} + SR5688_KP(\.count) // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}} + // expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{15-15=?.}} + // expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{15-15=!.}} + let _ : KeyPath = \.count // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}} + // expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{37-37=?.}} + // expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{37-37=!.}} } func testSyntaxErrors() { From 4c7ccf5abe79563907bbfc0cd80899f0a3287476 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 25 Aug 2020 15:12:50 -0700 Subject: [PATCH 407/663] [NFC] Clean Up FrontendTool Try to impose a simple structure that splits performing actions from the pre and post-pipeline conditions. Wherever actions would take more than a simple return, split them into functions. Refine functions that perform effects to return status codes when they fail. Finally, delineate functions that need semantic analysis from those that do not. Overall this should be NFC. --- include/swift/Frontend/Frontend.h | 2 +- lib/Frontend/Frontend.cpp | 3 +- lib/FrontendTool/FrontendTool.cpp | 356 ++++++++++++++------------ lib/FrontendTool/ImportedModules.cpp | 4 +- lib/FrontendTool/ImportedModules.h | 3 +- lib/FrontendTool/ScanDependencies.cpp | 5 +- lib/FrontendTool/ScanDependencies.h | 3 +- 7 files changed, 204 insertions(+), 172 deletions(-) diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index f5f75f13e7694..39ab041dbcc1b 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -621,7 +621,7 @@ class CompilerInstance { /// /// This is similar to a parse-only invocation, but module imports will also /// be processed. - void performParseAndResolveImportsOnly(); + bool performParseAndResolveImportsOnly(); /// Performs mandatory, diagnostic, and optimization passes over the SIL. /// \param silModule The SIL module that was generated during SILGen. diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 0d6263b2e544c..688acbf0b29dd 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -848,7 +848,7 @@ void CompilerInstance::setMainModule(ModuleDecl *newMod) { Context->addLoadedModule(newMod); } -void CompilerInstance::performParseAndResolveImportsOnly() { +bool CompilerInstance::performParseAndResolveImportsOnly() { FrontendStatsTracer tracer(getStatsReporter(), "parse-and-resolve-imports"); // Resolve imports for all the source files. @@ -867,6 +867,7 @@ void CompilerInstance::performParseAndResolveImportsOnly() { mainModule->setHasResolvedImports(); bindExtensions(*mainModule); + return Context->hadError(); } void CompilerInstance::performSema() { diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 4221b53394e5f..743205b9ccb44 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1229,7 +1229,7 @@ static void verifyGenericSignaturesIfNeeded(const CompilerInvocation &Invocation GenericSignatureBuilder::verifyGenericSignaturesInModule(module); } -static void dumpAndPrintScopeMap(const CompilerInstance &Instance, +static bool dumpAndPrintScopeMap(const CompilerInstance &Instance, SourceFile *SF) { // Not const because may require reexpansion ASTScope &scope = SF->getScope(); @@ -1239,13 +1239,14 @@ static void dumpAndPrintScopeMap(const CompilerInstance &Instance, llvm::errs() << "***Complete scope map***\n"; scope.buildFullyExpandedTree(); scope.print(llvm::errs()); - return; + return Instance.getASTContext().hadError(); } // Probe each of the locations, and dump what we find. for (auto lineColumn : opts.DumpScopeMapLocations) { scope.buildFullyExpandedTree(); scope.dumpOneScopeMapLocation(lineColumn); } + return Instance.getASTContext().hadError(); } static SourceFile * @@ -1260,7 +1261,7 @@ getPrimaryOrMainSourceFile(const CompilerInstance &Instance) { /// Dumps the AST of all available primary source files. If corresponding output /// files were specified, use them; otherwise, dump the AST to stdout. -static void dumpAST(CompilerInstance &Instance) { +static bool dumpAST(CompilerInstance &Instance) { auto primaryFiles = Instance.getPrimarySourceFiles(); if (!primaryFiles.empty()) { for (SourceFile *sourceFile: primaryFiles) { @@ -1275,55 +1276,7 @@ static void dumpAST(CompilerInstance &Instance) { auto *SF = getPrimaryOrMainSourceFile(Instance); SF->dump(llvm::outs(), /*parseIfNeeded*/ true); } -} - -/// We may have been told to dump the AST (either after parsing or -/// type-checking, which is already differentiated in -/// CompilerInstance::performSema()), so dump or print the main source file and -/// return. - -static Optional dumpASTIfNeeded(CompilerInstance &Instance) { - const auto &opts = Instance.getInvocation().getFrontendOptions(); - const FrontendOptions::ActionType Action = opts.RequestedAction; - ASTContext &Context = Instance.getASTContext(); - switch (Action) { - default: - return None; - - case FrontendOptions::ActionType::PrintAST: - getPrimaryOrMainSourceFile(Instance) - ->print(llvm::outs(), PrintOptions::printEverything()); - break; - - case FrontendOptions::ActionType::DumpScopeMaps: - dumpAndPrintScopeMap(Instance, getPrimaryOrMainSourceFile(Instance)); - break; - - case FrontendOptions::ActionType::DumpTypeRefinementContexts: - getPrimaryOrMainSourceFile(Instance) - ->getTypeRefinementContext() - ->dump(llvm::errs(), Context.SourceMgr); - break; - - case FrontendOptions::ActionType::DumpInterfaceHash: - getPrimaryOrMainSourceFile(Instance)->dumpInterfaceHash(llvm::errs()); - break; - - case FrontendOptions::ActionType::EmitSyntax: - emitSyntax(getPrimaryOrMainSourceFile(Instance), - opts.InputsAndOutputs.getSingleOutputFilename()); - break; - - case FrontendOptions::ActionType::DumpParse: - case FrontendOptions::ActionType::DumpAST: - dumpAST(Instance); - break; - - case FrontendOptions::ActionType::EmitImportedModules: - emitImportedModules(Context, Instance.getMainModule(), opts); - break; - } - return Context.hadError(); + return Instance.getASTContext().hadError(); } static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded( @@ -1747,40 +1700,187 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { emitCompiledSourceForAllPrimaryInputsIfNeeded(Instance); } -/// Performs the compile requested by the user. -/// \param Instance Will be reset after performIRGeneration when the verifier -/// mode is NoVerify and there were no errors. -/// \returns true on error -static bool performCompile(CompilerInvocation &Invok, - CompilerInstance &Instance, - ArrayRef Args, - int &ReturnValue, - FrontendObserver *observer) { +static bool printSwiftVersion(const CompilerInvocation &Invocation) { + llvm::outs() << version::getSwiftFullVersion( + version::Version::getCurrentLanguageVersion()) + << '\n'; + llvm::outs() << "Target: " << Invocation.getLangOptions().Target.str() + << '\n'; + return false; +} + +static bool +withSemanticAnalysis(CompilerInstance &Instance, FrontendObserver *observer, + llvm::function_ref cont) { const auto &Invocation = Instance.getInvocation(); const auto &opts = Invocation.getFrontendOptions(); - const FrontendOptions::ActionType Action = opts.RequestedAction; + assert(!FrontendOptions::shouldActionOnlyParse(opts.RequestedAction) && + "Action may only parse, but has requested semantic analysis!"); + + Instance.performSema(); + if (observer) + observer->performedSemanticAnalysis(Instance); + + switch (opts.CrashMode) { + case FrontendOptions::DebugCrashMode::AssertAfterParse: + debugFailWithAssertion(); + return true; + case FrontendOptions::DebugCrashMode::CrashAfterParse: + debugFailWithCrash(); + return true; + case FrontendOptions::DebugCrashMode::None: + break; + } + + (void)migrator::updateCodeAndEmitRemapIfNeeded(&Instance); + + if (Instance.getASTContext().hadError()) + return true; + + return cont(Instance); +} + +static bool performScanDependencies(CompilerInstance &Instance) { + auto batchScanInput = + Instance.getASTContext().SearchPathOpts.BatchScanInputFilePath; + if (batchScanInput.empty()) { + return scanDependencies(Instance); + } else { + return batchScanModuleDependencies(Instance, batchScanInput); + } +} + +static bool performParseOnly(ModuleDecl &MainModule) { + // A -parse invocation only cares about the side effects of parsing, so + // force the parsing of all the source files. + for (auto *file : MainModule.getFiles()) { + if (auto *SF = dyn_cast(file)) + (void)SF->getTopLevelDecls(); + } + return MainModule.getASTContext().hadError(); +} + +static bool performAction(CompilerInstance &Instance, + int &ReturnValue, + FrontendObserver *observer) { + const auto &opts = Instance.getInvocation().getFrontendOptions(); + auto &Context = Instance.getASTContext(); + switch (Instance.getInvocation().getFrontendOptions().RequestedAction) { + // MARK: Trivial Actions + case FrontendOptions::ActionType::NoneAction: + return Context.hadError(); + case FrontendOptions::ActionType::PrintVersion: + return printSwiftVersion(Instance.getInvocation()); + case FrontendOptions::ActionType::REPL: + llvm::report_fatal_error("Compiler-internal integrated REPL has been " + "removed; use the LLDB-enhanced REPL instead."); + // MARK: Actions for Clang and Clang Modules // We've been asked to precompile a bridging header or module; we want to // avoid touching any other inputs and just parse, emit and exit. - if (Action == FrontendOptions::ActionType::EmitPCH) + case FrontendOptions::ActionType::EmitPCH: return precompileBridgingHeader(Instance); - if (Action == FrontendOptions::ActionType::EmitPCM) + case FrontendOptions::ActionType::EmitPCM: return precompileClangModule(Instance); - if (Action == FrontendOptions::ActionType::DumpPCM) + case FrontendOptions::ActionType::DumpPCM: return dumpPrecompiledClangModule(Instance); - if (Action == FrontendOptions::ActionType::PrintVersion) { - llvm::outs() << version::getSwiftFullVersion( - version::Version::getCurrentLanguageVersion()) << '\n'; - llvm::outs() << "Target: " - << Invocation.getLangOptions().Target.str() << '\n'; - return false; - } - if (Action == FrontendOptions::ActionType::CompileModuleFromInterface || - Action == FrontendOptions::ActionType::TypecheckModuleFromInterface) + + // MARK: Module Interface Actions + case FrontendOptions::ActionType::CompileModuleFromInterface: + case FrontendOptions::ActionType::TypecheckModuleFromInterface: return buildModuleFromInterface(Instance); - if (Invocation.getInputKind() == InputFileKind::LLVM) - return compileLLVMIR(Instance); + // MARK: Actions that Dump + case FrontendOptions::ActionType::DumpParse: { + return dumpAST(Instance); + } + case FrontendOptions::ActionType::DumpAST: + return withSemanticAnalysis( + Instance, observer, + [](CompilerInstance &Instance) { return dumpAST(Instance); }); + case FrontendOptions::ActionType::PrintAST: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + getPrimaryOrMainSourceFile(Instance)->print( + llvm::outs(), PrintOptions::printEverything()); + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::DumpScopeMaps: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + return dumpAndPrintScopeMap(Instance, + getPrimaryOrMainSourceFile(Instance)); + }); + case FrontendOptions::ActionType::DumpTypeRefinementContexts: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + getPrimaryOrMainSourceFile(Instance) + ->getTypeRefinementContext() + ->dump(llvm::errs(), Instance.getASTContext().SourceMgr); + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::DumpInterfaceHash: + getPrimaryOrMainSourceFile(Instance)->dumpInterfaceHash(llvm::errs()); + return Context.hadError(); + case FrontendOptions::ActionType::EmitSyntax: + return emitSyntax(getPrimaryOrMainSourceFile(Instance), + opts.InputsAndOutputs.getSingleOutputFilename()); + case FrontendOptions::ActionType::EmitImportedModules: + return emitImportedModules(Instance.getMainModule(), opts); + + // MARK: Dependency Scanning Actions + case FrontendOptions::ActionType::ScanDependencies: + return performScanDependencies(Instance); + case FrontendOptions::ActionType::ScanClangDependencies: + return scanClangDependencies(Instance); + + // MARK: General Compilation Actions + case FrontendOptions::ActionType::Parse: + return performParseOnly(*Instance.getMainModule()); + case FrontendOptions::ActionType::ResolveImports: + return Instance.performParseAndResolveImportsOnly(); + case FrontendOptions::ActionType::Typecheck: + return withSemanticAnalysis(Instance, observer, + [](CompilerInstance &Instance) { + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::EmitSILGen: + case FrontendOptions::ActionType::EmitSIBGen: + case FrontendOptions::ActionType::EmitSIL: + case FrontendOptions::ActionType::EmitSIB: + case FrontendOptions::ActionType::EmitModuleOnly: + case FrontendOptions::ActionType::MergeModules: + case FrontendOptions::ActionType::Immediate: + case FrontendOptions::ActionType::EmitAssembly: + case FrontendOptions::ActionType::EmitIR: + case FrontendOptions::ActionType::EmitBC: + case FrontendOptions::ActionType::EmitObject: + case FrontendOptions::ActionType::DumpTypeInfo: + return withSemanticAnalysis( + Instance, observer, [&](CompilerInstance &Instance) { + assert(FrontendOptions::doesActionGenerateSIL(opts.RequestedAction) && + "All actions not requiring SILGen must have been handled!"); + if (Instance.getInvocation().getInputKind() == InputFileKind::LLVM) + return compileLLVMIR(Instance); + + return performCompileStepsPostSema(Instance, ReturnValue, observer); + }); + } + + assert(false && "Unhandled case in performCompile!"); + return Context.hadError(); +} + +/// Performs the compile requested by the user. +/// \param Instance Will be reset after performIRGeneration when the verifier +/// mode is NoVerify and there were no errors. +/// \returns true on error +static bool performCompile(CompilerInstance &Instance, + int &ReturnValue, + FrontendObserver *observer) { + const auto &Invocation = Instance.getInvocation(); + const auto &opts = Invocation.getFrontendOptions(); + const FrontendOptions::ActionType Action = opts.RequestedAction; // If we aren't in a parse-only context and expect an implicit stdlib import, // load in the standard library. If we either fail to find it or encounter an @@ -1793,95 +1893,27 @@ static bool performCompile(CompilerInvocation &Invok, return true; } - bool didFinishPipeline = false; - SWIFT_DEFER { - assert(didFinishPipeline && "Returned without calling finishPipeline"); - }; - - auto finishPipeline = [&](bool hadError) -> bool { - // We might have freed the ASTContext already, but in that case we would - // have already performed these actions. - if (Instance.hasASTContext()) { - performEndOfPipelineActions(Instance); - hadError |= Instance.getASTContext().hadError(); - } - didFinishPipeline = true; - return hadError; - }; - - auto &Context = Instance.getASTContext(); - if (FrontendOptions::shouldActionOnlyParse(Action)) { - // Parsing gets triggered lazily, but let's make sure we have the right - // input kind. - auto kind = Invocation.getInputKind(); - assert((kind == InputFileKind::Swift || - kind == InputFileKind::SwiftLibrary || - kind == InputFileKind::SwiftModuleInterface) && - "Only supports parsing .swift files"); - (void)kind; - } else if (Action == FrontendOptions::ActionType::ResolveImports) { - Instance.performParseAndResolveImportsOnly(); - return finishPipeline(Context.hadError()); - } else { - Instance.performSema(); - } - - if (Action == FrontendOptions::ActionType::Parse) { - // A -parse invocation only cares about the side effects of parsing, so - // force the parsing of all the source files. - for (auto *file : Instance.getMainModule()->getFiles()) { - if (auto *SF = dyn_cast(file)) - (void)SF->getTopLevelDecls(); + assert([&]() -> bool { + if (FrontendOptions::shouldActionOnlyParse(Action)) { + // Parsing gets triggered lazily, but let's make sure we have the right + // input kind. + auto kind = Invocation.getInputKind(); + return kind == InputFileKind::Swift || + kind == InputFileKind::SwiftLibrary || + kind == InputFileKind::SwiftModuleInterface; } - return finishPipeline(Context.hadError()); - } - - if (Action == FrontendOptions::ActionType::ScanDependencies) { - auto batchScanInput = Instance.getASTContext().SearchPathOpts.BatchScanInputFilePath; - if (batchScanInput.empty()) - return finishPipeline(scanDependencies(Instance)); - else - return finishPipeline(batchScanModuleDependencies(Invok, - Instance, - batchScanInput)); - } - - if (Action == FrontendOptions::ActionType::ScanClangDependencies) - return finishPipeline(scanClangDependencies(Instance)); - - if (observer) - observer->performedSemanticAnalysis(Instance); - - { - FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode; - if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse) - debugFailWithAssertion(); - else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse) - debugFailWithCrash(); - } + return true; + }() && "Only supports parsing .swift files"); - (void)migrator::updateCodeAndEmitRemapIfNeeded(&Instance); + bool hadError = performAction(Instance, ReturnValue, observer); - if (Action == FrontendOptions::ActionType::REPL) { - llvm::report_fatal_error("Compiler-internal integrated REPL has been " - "removed; use the LLDB-enhanced REPL instead."); + // We might have freed the ASTContext already, but in that case we would + // have already performed these actions. + if (Instance.hasASTContext()) { + performEndOfPipelineActions(Instance); + hadError |= Instance.getASTContext().hadError(); } - - if (auto r = dumpASTIfNeeded(Instance)) - return finishPipeline(*r); - - if (Context.hadError()) - return finishPipeline(/*hadError*/ true); - - // We've just been told to perform a typecheck, so we can return now. - if (Action == FrontendOptions::ActionType::Typecheck) - return finishPipeline(/*hadError*/ false); - - assert(FrontendOptions::doesActionGenerateSIL(Action) && - "All actions not requiring SILGen must have been handled!"); - - return finishPipeline( - performCompileStepsPostSema(Instance, ReturnValue, observer)); + return hadError; } static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, @@ -2655,7 +2687,7 @@ int swift::performFrontend(ArrayRef Args, } int ReturnValue = 0; - bool HadError = performCompile(Invocation, *Instance, Args, ReturnValue, observer); + bool HadError = performCompile(*Instance, ReturnValue, observer); if (verifierEnabled) { DiagnosticEngine &diags = Instance->getDiags(); diff --git a/lib/FrontendTool/ImportedModules.cpp b/lib/FrontendTool/ImportedModules.cpp index 90a33895ee52a..d750417737264 100644 --- a/lib/FrontendTool/ImportedModules.cpp +++ b/lib/FrontendTool/ImportedModules.cpp @@ -42,9 +42,9 @@ static void findAllClangImports(const clang::Module *module, } } -bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, +bool swift::emitImportedModules(ModuleDecl *mainModule, const FrontendOptions &opts) { - + auto &Context = mainModule->getASTContext(); std::string path = opts.InputsAndOutputs.getSingleOutputFilename(); std::error_code EC; llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None); diff --git a/lib/FrontendTool/ImportedModules.h b/lib/FrontendTool/ImportedModules.h index 42b4e76babaf4..510fa4ccdedde 100644 --- a/lib/FrontendTool/ImportedModules.h +++ b/lib/FrontendTool/ImportedModules.h @@ -20,8 +20,7 @@ class FrontendOptions; class ModuleDecl; /// Emit the names of the modules imported by \c mainModule. -bool emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, - const FrontendOptions &opts); +bool emitImportedModules(ModuleDecl *mainModule, const FrontendOptions &opts); } // end namespace swift #endif diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index fb0cd4b47a0bc..34e99395e1b17 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -690,9 +690,10 @@ bool swift::scanClangDependencies(CompilerInstance &instance) { .InputsAndOutputs.getSingleOutputFilename()); } -bool swift::batchScanModuleDependencies(CompilerInvocation &invok, - CompilerInstance &instance, +bool swift::batchScanModuleDependencies(CompilerInstance &instance, llvm::StringRef batchInputFile) { + const CompilerInvocation &invok = instance.getInvocation(); + (void)instance.getMainModule(); llvm::BumpPtrAllocator alloc; llvm::StringSaver saver(alloc); diff --git a/lib/FrontendTool/ScanDependencies.h b/lib/FrontendTool/ScanDependencies.h index 4604496ba66dc..fab7d26bbb190 100644 --- a/lib/FrontendTool/ScanDependencies.h +++ b/lib/FrontendTool/ScanDependencies.h @@ -21,8 +21,7 @@ class CompilerInvocation; class CompilerInstance; /// Batch scan the dependencies for modules specified in \c batchInputFile. -bool batchScanModuleDependencies(CompilerInvocation &invok, - CompilerInstance &instance, +bool batchScanModuleDependencies(CompilerInstance &instance, llvm::StringRef batchInputFile); /// Scans the dependencies of the main module of \c instance. From fe7444ffa3e3ac61da5194102c57e6c451156c88 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 27 Aug 2020 12:10:13 -0700 Subject: [PATCH 408/663] Add doesActionRequireSwiftStandardLibrary --- include/swift/Frontend/FrontendOptions.h | 6 ++- lib/Frontend/FrontendOptions.cpp | 59 ++++++++++++++++++++---- lib/FrontendTool/FrontendTool.cpp | 2 +- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 724cf7e6efa31..0d3a0e68de7f1 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -294,9 +294,13 @@ class FrontendOptions { /// '.../lib/swift', otherwise '.../lib/swift_static'. bool UseSharedResourceFolder = true; - /// \return true if action only parses without doing other compilation steps. + /// \return true if the given action only parses without doing other compilation steps. static bool shouldActionOnlyParse(ActionType); + /// \return true if the given action requires the standard library to be + /// loaded before it is run. + static bool doesActionRequireSwiftStandardLibrary(ActionType); + /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 83718a733666e..013a83157bf9d 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -73,20 +73,63 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { bool FrontendOptions::shouldActionOnlyParse(ActionType action) { switch (action) { - case FrontendOptions::ActionType::Parse: - case FrontendOptions::ActionType::DumpParse: - case FrontendOptions::ActionType::EmitSyntax: - case FrontendOptions::ActionType::DumpInterfaceHash: - case FrontendOptions::ActionType::EmitImportedModules: - case FrontendOptions::ActionType::ScanDependencies: - case FrontendOptions::ActionType::ScanClangDependencies: - case FrontendOptions::ActionType::PrintVersion: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::PrintVersion: return true; default: return false; } } +bool FrontendOptions::doesActionRequireSwiftStandardLibrary(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::PrintVersion: + case ActionType::EmitPCH: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + return false; + case ActionType::ResolveImports: + case ActionType::Typecheck: + case ActionType::DumpAST: + case ActionType::PrintAST: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitModuleOnly: + case ActionType::MergeModules: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitAssembly: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitObject: + case ActionType::DumpTypeInfo: + assert(!FrontendOptions::shouldActionOnlyParse(action) && + "Parse-only actions should not load modules!"); + return true; + } + llvm_unreachable("Unknown ActionType"); +} + void FrontendOptions::forAllOutputPaths( const InputFile &input, llvm::function_ref fn) const { if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly && diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 743205b9ccb44..0d28ccf3d2ace 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1888,7 +1888,7 @@ static bool performCompile(CompilerInstance &Instance, // trigger a bunch of other errors due to the stdlib being missing, or at // worst crash downstream as many call sites don't currently handle a missing // stdlib. - if (!FrontendOptions::shouldActionOnlyParse(Action)) { + if (FrontendOptions::doesActionRequireSwiftStandardLibrary(Action)) { if (Instance.loadStdlibIfNeeded()) return true; } From 4c56c95674a12342d4321ab78003a9fe983581c7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 27 Aug 2020 16:13:47 -0700 Subject: [PATCH 409/663] Define doesActionRequireInputs --- include/swift/Frontend/FrontendOptions.h | 3 ++ .../ArgsToFrontendOptionsConverter.cpp | 3 +- lib/Frontend/FrontendOptions.cpp | 41 +++++++++++++++++++ lib/FrontendTool/FrontendTool.cpp | 34 ++++++++++----- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 0d3a0e68de7f1..c961794d35582 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -301,6 +301,9 @@ class FrontendOptions { /// loaded before it is run. static bool doesActionRequireSwiftStandardLibrary(ActionType); + /// \return true if the given action requires input files to be provided. + static bool doesActionRequireInputs(ActionType action); + /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 4e12495bb35df..c876a44f87383 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -406,8 +406,7 @@ bool ArgsToFrontendOptionsConverter::setUpInputKindAndImmediateArgs() { if (Opts.InputsAndOutputs.verifyInputs( Diags, treatAsSIL, Opts.RequestedAction == FrontendOptions::ActionType::REPL, - (Opts.RequestedAction == FrontendOptions::ActionType::NoneAction || - Opts.RequestedAction == FrontendOptions::ActionType::PrintVersion))){ + !FrontendOptions::doesActionRequireInputs(Opts.RequestedAction))) { return true; } if (Opts.RequestedAction == FrontendOptions::ActionType::Immediate) { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 013a83157bf9d..16fe1877a6d25 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -130,6 +130,47 @@ bool FrontendOptions::doesActionRequireSwiftStandardLibrary(ActionType action) { llvm_unreachable("Unknown ActionType"); } +bool FrontendOptions::doesActionRequireInputs(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::PrintVersion: + return false; + case ActionType::REPL: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::EmitPCH: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + case ActionType::ResolveImports: + case ActionType::Typecheck: + case ActionType::DumpAST: + case ActionType::PrintAST: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitModuleOnly: + case ActionType::MergeModules: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::Immediate: + case ActionType::EmitAssembly: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitObject: + case ActionType::DumpTypeInfo: + return true; + } + llvm_unreachable("Unknown ActionType"); +} + void FrontendOptions::forAllOutputPaths( const InputFile &input, llvm::function_ref fn) const { if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly && diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 0d28ccf3d2ace..f4b42016d7d46 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1653,6 +1653,7 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { // it's -emit-imported-modules, which can load modules. auto action = opts.RequestedAction; if (FrontendOptions::shouldActionOnlyParse(action) && + !ctx.getLoadedModules().empty() && action != FrontendOptions::ActionType::EmitImportedModules) { assert(ctx.getNumLoadedModules() == 1 && "Loaded a module during parse-only"); @@ -1689,9 +1690,15 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { } } - // Emit dependencies and index data. + // FIXME: This predicate matches the status quo, but there's no reason + // indexing cannot run for actions that do not require stdlib e.g. to better + // facilitate tests. + if (FrontendOptions::doesActionRequireSwiftStandardLibrary(action)) { + emitIndexData(Instance); + } + + // Emit dependencies. emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Instance); - emitIndexData(Instance); emitMakeDependenciesIfNeeded(Instance.getDiags(), Instance.getDependencyTracker(), opts); @@ -1791,13 +1798,16 @@ static bool performAction(CompilerInstance &Instance, return buildModuleFromInterface(Instance); // MARK: Actions that Dump - case FrontendOptions::ActionType::DumpParse: { + case FrontendOptions::ActionType::DumpParse: + return dumpAST(Instance); + case FrontendOptions::ActionType::DumpAST: { + // FIXME: -dump-ast expects to be able to write output even if type checking + // fails which does not cleanly fit the model \c withSemanticAnalysis is + // trying to impose. Once there is a request for the "semantic AST", this + // point is moot. + Instance.performSema(); return dumpAST(Instance); } - case FrontendOptions::ActionType::DumpAST: - return withSemanticAnalysis( - Instance, observer, - [](CompilerInstance &Instance) { return dumpAST(Instance); }); case FrontendOptions::ActionType::PrintAST: return withSemanticAnalysis( Instance, observer, [](CompilerInstance &Instance) { @@ -1860,9 +1870,6 @@ static bool performAction(CompilerInstance &Instance, Instance, observer, [&](CompilerInstance &Instance) { assert(FrontendOptions::doesActionGenerateSIL(opts.RequestedAction) && "All actions not requiring SILGen must have been handled!"); - if (Instance.getInvocation().getInputKind() == InputFileKind::LLVM) - return compileLLVMIR(Instance); - return performCompileStepsPostSema(Instance, ReturnValue, observer); }); } @@ -1882,6 +1889,10 @@ static bool performCompile(CompilerInstance &Instance, const auto &opts = Invocation.getFrontendOptions(); const FrontendOptions::ActionType Action = opts.RequestedAction; + // To compile LLVM IR, just pass it off unmodified. + if (Instance.getInvocation().getInputKind() == InputFileKind::LLVM) + return compileLLVMIR(Instance); + // If we aren't in a parse-only context and expect an implicit stdlib import, // load in the standard library. If we either fail to find it or encounter an // error while loading it, bail early. Continuing the compilation will at best @@ -1909,7 +1920,8 @@ static bool performCompile(CompilerInstance &Instance, // We might have freed the ASTContext already, but in that case we would // have already performed these actions. - if (Instance.hasASTContext()) { + if (Instance.hasASTContext() && + FrontendOptions::doesActionRequireInputs(Action)) { performEndOfPipelineActions(Instance); hadError |= Instance.getASTContext().hadError(); } From e013ebd388cba978760cfd2c2cc604025de34a1b Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 27 Aug 2020 12:55:33 -0700 Subject: [PATCH 410/663] [CodeCompletion] Ensure all ExtensionDecl's extended nominal are computed Fixes an assertion failure in ASTScope lookup rdar://problem/67102794 --- lib/IDE/ExprContextAnalysis.cpp | 20 ++++++++++++++++++-- test/IDE/complete_type.swift | 14 ++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 787606e321891..6a4fff5f8c011 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -46,9 +46,11 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { while (isa(DC)) DC = DC->getParent(); - // Make sure the extension has been bound, in case it is in an inactive #if - // or something weird like that. + // Make sure the extension has been bound. { + // Even if the extension is invalid (e.g. nested in a function or another + // type), we want to know the "intended nominal" of the extension so that + // we can know the type of 'Self'. SmallVector extensions; for (auto typeCtx = DC->getInnermostTypeContext(); typeCtx != nullptr; typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { @@ -59,6 +61,20 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { extensions.back()->computeExtendedNominal(); extensions.pop_back(); } + + // If the completion happens in the inheritance clause of the extension, + // 'DC' is the parent of the extension. We need to iterate the top level + // decls to find it. In theory, we don't need the extended nominal in the + // inheritance clause, but ASTScope lookup requires that. We don't care + // unless 'DC' is not 'SourceFile' because non-toplevel extensions are + // 'canNeverBeBound()' anyway. + if (auto *SF = dyn_cast(DC)) { + auto &SM = DC->getASTContext().SourceMgr; + for (auto *decl : SF->getTopLevelDecls()) + if (auto *ext = dyn_cast(decl)) + if (SM.rangeContainsTokenLoc(ext->getSourceRange(), Loc)) + ext->computeExtendedNominal(); + } } // Type-check this context. diff --git a/test/IDE/complete_type.swift b/test/IDE/complete_type.swift index 04b9158fda578..4178ff2840b04 100644 --- a/test/IDE/complete_type.swift +++ b/test/IDE/complete_type.swift @@ -765,3 +765,17 @@ func testUnbound2(x: OuterStruct.Inner.#^UNBOUND_DOT_3^#) {} // UNBOUND_DOT_3: Begin completions // UNBOUND_DOT_3-DAG: Keyword/None: Type[#OuterStruct.Inner.Type#]; name=Type // UNBOUND_DOT_3: End completions + +// rdar://problem/67102794 +struct HasProtoAlias { + typealias ProtoAlias = FooProtocol +} +extension FooStruct: HasProtoAlias.#^EXTENSION_INHERITANCE_1?check=EXTENSION_INHERITANCE^# {} + +struct ContainExtension { + extension FooStruct: HasProtoAlias.#^EXTENSION_INHERITANCE_2?check=EXTENSION_INHERITANCE^# {} +} +// EXTENSION_INHERITANCE: Begin completions, 2 items +// EXTENSION_INHERITANCE-DAG: Decl[TypeAlias]/CurrNominal: ProtoAlias[#FooProtocol#]; +// EXTENSION_INHERITANCE-DAG: Keyword/None: Type[#HasProtoAlias.Type#]; +// EXTENSION_INHERITANCE: End completions From 16876fbf6617c40df326df7d3fe00a15ff77448b Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 24 Aug 2020 13:56:23 -0700 Subject: [PATCH 411/663] [Clang importer] Drop unused parameter from getParamOptionality(). This operation is not actually dependent on the version. --- lib/ClangImporter/ClangAdapter.cpp | 3 +-- lib/ClangImporter/ClangAdapter.h | 6 +----- lib/ClangImporter/ImportName.cpp | 5 +---- lib/ClangImporter/ImportType.cpp | 6 ++---- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp index eddac5d46b3bf..a2ff1426bf477 100644 --- a/lib/ClangImporter/ClangAdapter.cpp +++ b/lib/ClangImporter/ClangAdapter.cpp @@ -714,8 +714,7 @@ bool importer::isUnavailableInSwift( return false; } -OptionalTypeKind importer::getParamOptionality(version::Version swiftVersion, - const clang::ParmVarDecl *param, +OptionalTypeKind importer::getParamOptionality(const clang::ParmVarDecl *param, bool knownNonNull) { auto &clangCtx = param->getASTContext(); diff --git a/lib/ClangImporter/ClangAdapter.h b/lib/ClangImporter/ClangAdapter.h index 0b066364bd622..9a15bbd523efa 100644 --- a/lib/ClangImporter/ClangAdapter.h +++ b/lib/ClangImporter/ClangAdapter.h @@ -161,15 +161,11 @@ bool isUnavailableInSwift(const clang::Decl *decl, const PlatformAvailability &, /// Determine the optionality of the given Clang parameter. /// -/// \param swiftLanguageVersion What version of Swift we're using, which affects -/// how optionality is inferred. -/// /// \param param The Clang parameter. /// /// \param knownNonNull Whether a function- or method-level "nonnull" attribute /// applies to this parameter. -OptionalTypeKind getParamOptionality(version::Version swiftLanguageVersion, - const clang::ParmVarDecl *param, +OptionalTypeKind getParamOptionality(const clang::ParmVarDecl *param, bool knownNonNull); } } diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 46817ce93de2a..088b62ea3d2a6 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -807,8 +807,6 @@ static bool omitNeedlessWordsInFunctionName( Optional errorParamIndex, bool returnsSelf, bool isInstanceMethod, NameImporter &nameImporter) { clang::ASTContext &clangCtx = nameImporter.getClangContext(); - const version::Version &swiftLanguageVersion = - nameImporter.getLangOpts().EffectiveLanguageVersion; // Collect the parameter type names. StringRef firstParamName; @@ -837,8 +835,7 @@ static bool omitNeedlessWordsInFunctionName( bool hasDefaultArg = ClangImporter::Implementation::inferDefaultArgument( param->getType(), - getParamOptionality(swiftLanguageVersion, param, - !nonNullArgs.empty() && nonNullArgs[i]), + getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[i]), nameImporter.getIdentifier(baseName), argumentName, i == 0, isLastParameter, nameImporter) != DefaultArgumentKind::None; diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index a13fb40d28210..69034c5c3778e 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1747,8 +1747,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( // Check nullability of the parameter. OptionalTypeKind OptionalityOfParam = - getParamOptionality(SwiftContext.LangOpts.EffectiveLanguageVersion, - param, !nonNullArgs.empty() && nonNullArgs[index]); + getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[index]); ImportTypeKind importKind = ImportTypeKind::Parameter; if (param->hasAttr()) @@ -2127,8 +2126,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( // Check nullability of the parameter. OptionalTypeKind optionalityOfParam - = getParamOptionality(SwiftContext.LangOpts.EffectiveLanguageVersion, - param, + = getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[paramIndex]); bool allowNSUIntegerAsIntInParam = isFromSystemModule; From 6e8ee7cc49f0443ed929640ab82192858b4f4f67 Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Fri, 28 Aug 2020 04:10:37 +0200 Subject: [PATCH 412/663] [docs] Fix small mistake in DynamicCasting.md (#33641) Foundation has no `Number` type. --- docs/DynamicCasting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md index add2524d59e33..1ef306549a148 100644 --- a/docs/DynamicCasting.md +++ b/docs/DynamicCasting.md @@ -191,7 +191,7 @@ Implementation Note: `AnyObject` is represented in memory as a pointer to a refc ### Objective-C Interactions Note the invariant above cannot be an equality because Objective-C bridging allows libraries to introduce new relationships that can alter the behavior of seemingly-unrelated casts. -One example of this is Foundation's `Number` (or `NSNumber`) type which conditionally bridges to several Swift numeric types. +One example of this is Foundation's `NSNumber` type which conditionally bridges to several Swift numeric types. As a result, when Foundation is in scope, `Int(7) is Double == false` but `(Int(7) as! AnyObject) is Double == true`. In general, the ability to add new bridging behaviors from a single type to several distinct types implies that Swift casting cannot be transitive. From 5afbddb42bbfc15dda8d6c286dd69033aa4a1a59 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 27 Aug 2020 19:21:53 -0700 Subject: [PATCH 413/663] [Dependency Scanner] Ensure that Clang dependency scanner instances inherit the creating invocation's extra clang args. This ensures that when the dependency scanner is invoked with additional clang (`-Xcc`) options, the Clang scanner is correctly configured using these options. --- .../ClangModuleDependencyScanner.cpp | 2 + test/ScanDependencies/Inputs/CHeaders/G.h | 5 ++ test/ScanDependencies/Inputs/CHeaders/X.h | 1 + .../Inputs/CHeaders/module.modulemap | 5 ++ .../batch_module_scan_versioned.swift | 49 +++++++++++++++++++ .../can_import_placeholder.swift | 2 +- .../diagnose_dependency_cycle.swift | 2 +- test/ScanDependencies/module_deps.swift | 3 +- .../module_deps_clang_only.swift | 2 +- .../module_deps_cross_import_overlay.swift | 2 +- .../module_deps_external.swift | 2 +- .../module_deps_private_interface.swift | 2 +- test/ScanDependencies/module_framework.swift | 2 +- 13 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 test/ScanDependencies/Inputs/CHeaders/X.h create mode 100644 test/ScanDependencies/batch_module_scan_versioned.swift diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index 290dd69506ed2..85e517b6ce435 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -308,6 +308,7 @@ Optional ClangImporter::getModuleDependencies( // Reform the Clang importer options. // FIXME: Just save a reference or copy so we can get this back. ClangImporterOptions importerOpts; + importerOpts.ExtraArgs = getExtraClangArgs(); // Determine the command-line arguments for dependency scanning. auto &ctx = Impl.SwiftContext; @@ -351,6 +352,7 @@ bool ClangImporter::addBridgingHeaderDependencies( // Reform the Clang importer options. // FIXME: Just save a reference or copy so we can get this back. ClangImporterOptions importerOpts; + importerOpts.ExtraArgs = getExtraClangArgs(); // Retrieve the bridging header. std::string bridgingHeader = *targetModule.getBridgingHeader(); diff --git a/test/ScanDependencies/Inputs/CHeaders/G.h b/test/ScanDependencies/Inputs/CHeaders/G.h index ef09c49a98e0f..4da23ffcbb4f6 100644 --- a/test/ScanDependencies/Inputs/CHeaders/G.h +++ b/test/ScanDependencies/Inputs/CHeaders/G.h @@ -1 +1,6 @@ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000 +#include "X.h" +#endif + void funcG(void); + diff --git a/test/ScanDependencies/Inputs/CHeaders/X.h b/test/ScanDependencies/Inputs/CHeaders/X.h new file mode 100644 index 0000000000000..11c123884ef12 --- /dev/null +++ b/test/ScanDependencies/Inputs/CHeaders/X.h @@ -0,0 +1 @@ +void funcX(void); diff --git a/test/ScanDependencies/Inputs/CHeaders/module.modulemap b/test/ScanDependencies/Inputs/CHeaders/module.modulemap index 481266591c912..95fc7fef133c2 100644 --- a/test/ScanDependencies/Inputs/CHeaders/module.modulemap +++ b/test/ScanDependencies/Inputs/CHeaders/module.modulemap @@ -37,3 +37,8 @@ module I { header "I.h" export * } + +module X { + header "X.h" + export * +} diff --git a/test/ScanDependencies/batch_module_scan_versioned.swift b/test/ScanDependencies/batch_module_scan_versioned.swift new file mode 100644 index 0000000000000..02725a2ff0160 --- /dev/null +++ b/test/ScanDependencies/batch_module_scan_versioned.swift @@ -0,0 +1,49 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: %empty-directory(%t/outputs) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: echo "[{" > %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"G\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-Xcc -target -Xcc x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/G_109.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}," >> %/t/inputs/input.json +// RUN: echo "{" >> %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"G\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-Xcc -target -Xcc x86_64-apple-macosx11.0\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/G_110.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}]" >> %/t/inputs/input.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix=CHECK-PCM109 < %t/outputs/G_109.pcm.json +// RUN: %FileCheck %s -check-prefix=CHECK-PCM110 < %t/outputs/G_110.pcm.json + +// CHECK-PCM109: { +// CHECK-PCM109-NEXT: "mainModuleName": "G", +// CHECK-PCM109-NEXT: "modules": [ +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "clang": "G" +// CHECK-PCM109-NEXT: }, +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "modulePath": "G.pcm", +// CHECK-PCM109: "directDependencies": [ +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "clang": "X" +// CHECK-PCM109-NEXT: } +// CHECK-PCM109-NEXT: ], +// CHECK-PCM109: "-I + +// CHECK-PCM110: { +// CHECK-PCM110-NEXT: "mainModuleName": "G", +// CHECK-PCM110-NEXT: "modules": [ +// CHECK-PCM110-NEXT: { +// CHECK-PCM110-NEXT: "clang": "G" +// CHECK-PCM110-NEXT: }, +// CHECK-PCM110-NEXT: { +// CHECK-PCM110-NEXT: "modulePath": "G.pcm", +// CHECK-PCM110: "directDependencies": [ +// CHECK-PCM110-NEXT: ], +// CHECK-PCM110-NOT: "clang": "X" +// CHECK-PCM110: "-I diff --git a/test/ScanDependencies/can_import_placeholder.swift b/test/ScanDependencies/can_import_placeholder.swift index 8b64644fc9a9b..8c14c6b2a125e 100644 --- a/test/ScanDependencies/can_import_placeholder.swift +++ b/test/ScanDependencies/can_import_placeholder.swift @@ -20,7 +20,7 @@ // RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/diagnose_dependency_cycle.swift b/test/ScanDependencies/diagnose_dependency_cycle.swift index 1157d364a7954..609fd331646eb 100644 --- a/test/ScanDependencies/diagnose_dependency_cycle.swift +++ b/test/ScanDependencies/diagnose_dependency_cycle.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules &> %t/out.txt +// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 &> %t/out.txt // RUN: %FileCheck %s < %t/out.txt diff --git a/test/ScanDependencies/module_deps.swift b/test/ScanDependencies/module_deps.swift index 05b6f15c322fb..dc48ba5e0998d 100644 --- a/test/ScanDependencies/module_deps.swift +++ b/test/ScanDependencies/module_deps.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json @@ -105,7 +105,6 @@ import SubE // CHECK-NEXT: "-only-use-extra-clang-opts" // CHECK-NEXT: "-Xcc" // CHECK-NEXT: "clang" -// CHECK: "-fno-implicit-modules" /// --------Swift module E // CHECK: "swift": "E" diff --git a/test/ScanDependencies/module_deps_clang_only.swift b/test/ScanDependencies/module_deps_clang_only.swift index e406bacd74889..34ac0c6eeefd1 100644 --- a/test/ScanDependencies/module_deps_clang_only.swift +++ b/test/ScanDependencies/module_deps_clang_only.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-clang-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules -module-name C +// RUN: %target-swift-frontend -scan-clang-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -module-name C // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_cross_import_overlay.swift b/test/ScanDependencies/module_deps_cross_import_overlay.swift index 7b1bfd9b63363..94031c4ce38bc 100644 --- a/test/ScanDependencies/module_deps_cross_import_overlay.swift +++ b/test/ScanDependencies/module_deps_cross_import_overlay.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_external.swift b/test/ScanDependencies/module_deps_external.swift index c7eb47a7f4e87..f3b2147a487da 100644 --- a/test/ScanDependencies/module_deps_external.swift +++ b/test/ScanDependencies/module_deps_external.swift @@ -20,7 +20,7 @@ // RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_private_interface.swift b/test/ScanDependencies/module_deps_private_interface.swift index bbf0a2dfbd053..2098775216ea8 100644 --- a/test/ScanDependencies/module_deps_private_interface.swift +++ b/test/ScanDependencies/module_deps_private_interface.swift @@ -6,7 +6,7 @@ // RUN: cp %t/Foo.swiftinterface %t/Foo.private.swiftinterface -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_framework.swift b/test/ScanDependencies/module_framework.swift index 937667d98d025..9756277074277 100644 --- a/test/ScanDependencies/module_framework.swift +++ b/test/ScanDependencies/module_framework.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -Xcc -Xclang // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json From b1db77adff4ee91bc24b24652d04c67487da68b4 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 27 Aug 2020 20:42:23 -0700 Subject: [PATCH 414/663] Fix ConnectionGraph verification for calls to no return functions. (#33655) Functions that do not have a return, and instead end with 'unreachable' due to NoReturnFolding will not have a ReturnNode in the connection graph. A caller calling a no return function then may not have a CGNode corresponding to the call's result. Fix the ConnectionGraph's verifier so we don't assert in such cases. --- lib/SILOptimizer/Analysis/EscapeAnalysis.cpp | 7 ++++++ test/SILOptimizer/escape_analysis.sil | 24 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 594cb81485a8c..c651cb5bf2943 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -1623,6 +1623,13 @@ void EscapeAnalysis::ConnectionGraph::verify() const { if (auto ai = dyn_cast(&i)) { if (EA->canOptimizeArrayUninitializedCall(ai).isValid()) continue; + // Ignore checking CGNode mapping for result of apply to a no return + // function that will have a null ReturnNode + if (auto *callee = ai->getReferencedFunctionOrNull()) { + if (EA->getFunctionInfo(callee)->isValid()) + if (!EA->getConnectionGraph(callee)->getReturnNodeOrNull()) + continue; + } } for (auto result : i.getResults()) { if (EA->getPointerBase(result)) diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil index bc8b42ba2426d..21944bbe21603 100644 --- a/test/SILOptimizer/escape_analysis.sil +++ b/test/SILOptimizer/escape_analysis.sil @@ -1983,3 +1983,27 @@ bb4: %z = tuple () return %z : $() } + +// Test CGNode mapping for result of an apply to no return function +// CHECK-LABEL:CG of $testcaller +// CHECK: Arg [ref] %0 Esc: A, Succ: (%0.1) +// CHECK: Con [int] %0.1 Esc: A, Succ: (%0.2) +// CHECK: Con [ref] %0.2 Esc: A, Succ: +// CHECK-LABEL:End +sil hidden [noinline] @$testcaller : $@convention(thin) (@owned Z) -> () { +bb0(%0 : $Z): + %2 = function_ref @$noreturncallee : $@convention(thin) (@guaranteed Z) -> @owned Z + %3 = apply %2(%0) : $@convention(thin) (@guaranteed Z) -> @owned Z + dealloc_ref %3 : $Z + %5 = tuple () + return %5 : $() +} + +// CHECK-LABEL:CG of $noreturncallee +// CHECK: Arg [ref] %0 Esc: A, Succ: +// CHECK-LABEL:End +sil hidden [noinline] @$noreturncallee : $@convention(thin) (@guaranteed Z) -> @owned Z { +bb0(%0 : $Z): + unreachable +} + From 1e5d30f5ca78204c8239cf4088fb4e1bebf141f7 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 26 Aug 2020 16:19:52 -0700 Subject: [PATCH 415/663] [Concurrency] Import Objective-C methods with completion handlers as async When a given Objective-C method has a completion handler parameter with an appropriate signature, import that Objective-C method as async. For example, consider the following CloudKit API: - (void)fetchShareParticipantWithUserRecordID:(CKRecordID *)userRecordID completionHandler:(void (^)(CKShareParticipant * _Nullable shareParticipant, NSError * _Nullable error))completionHandler; With the experimental concurrency model, this would import as: func fetchShareParticipant(withUserRecordID userRecordID: CKRecord.ID) async throws -> CKShare.Participant? The compiler will be responsible for turning the caller's continuation into a block to pass along to the completion handler. When the error parameter of the completion handler is non-null, the async call will result in that error being thrown. Otherwise, the other arguments passed to that completion handler will be returned as the result of the async call. async versions of methods are imported alongside their completion-handler versions, to maintain source compatibility with existing code that provides a completion handler. Note that this only covers the Clang importer portion of this task. --- include/swift/AST/Decl.h | 14 +- include/swift/AST/ForeignAsyncConvention.h | 81 ++++++++ include/swift/AST/ForeignErrorConvention.h | 23 ++- lib/AST/ASTContext.cpp | 23 +++ lib/AST/Decl.cpp | 5 +- lib/ClangImporter/ClangImporter.cpp | 7 + lib/ClangImporter/ImportDecl.cpp | 59 +++++- lib/ClangImporter/ImportName.cpp | 194 ++++++++++++++++++ lib/ClangImporter/ImportName.h | 61 +++++- lib/ClangImporter/ImportType.cpp | 55 +++++ lib/ClangImporter/SwiftLookupTable.cpp | 1 + test/ClangImporter/objc_async.swift | 22 ++ test/IDE/print_clang_objc_async.swift | 19 ++ .../usr/include/ObjCConcurrency.h | 14 ++ .../clang-importer-sdk/usr/include/module.map | 5 + utils/swift-api-dump.py | 4 + 16 files changed, 564 insertions(+), 23 deletions(-) create mode 100644 include/swift/AST/ForeignAsyncConvention.h create mode 100644 test/ClangImporter/objc_async.swift create mode 100644 test/IDE/print_clang_objc_async.swift create mode 100644 test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c21cac7948679..5842456999735 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -63,6 +63,7 @@ namespace swift { class Type; class Expr; class DeclRefExpr; + class ForeignAsyncConvention; class ForeignErrorConvention; class LiteralExpr; class BraceStmt; @@ -6148,7 +6149,15 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// being dropped altogether. `None` is returned for a normal function /// or method. Optional getForeignFunctionAsMethodSelfParameterIndex() const; - + + /// Set information about the foreign async convention used by this + /// declaration. + void setForeignAsyncConvention(const ForeignAsyncConvention &convention); + + /// Get information about the foreign async convention used by this + /// declaration, given that it is @objc and 'async'. + Optional getForeignAsyncConvention() const; + static bool classof(const Decl *D) { return D->getKind() >= DeclKind::First_AbstractFunctionDecl && D->getKind() <= DeclKind::Last_AbstractFunctionDecl; @@ -6277,7 +6286,8 @@ class FuncDecl : public AbstractFunctionDecl { DeclContext *Parent); static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, bool Throws, + DeclName Name, SourceLoc NameLoc, + bool Async, bool Throws, ParameterList *BodyParams, Type FnRetType, DeclContext *Parent, ClangNode ClangN); diff --git a/include/swift/AST/ForeignAsyncConvention.h b/include/swift/AST/ForeignAsyncConvention.h new file mode 100644 index 0000000000000..f3657766e02af --- /dev/null +++ b/include/swift/AST/ForeignAsyncConvention.h @@ -0,0 +1,81 @@ +//===--- ForeignAsyncConvention.h - Async conventions -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the ForeignAsyncConvention structure, which +// describes the rules for how to detect that a foreign API is asynchronous. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_FOREIGN_ASYNC_CONVENTION_H +#define SWIFT_FOREIGN_ASYNC_CONVENTION_H + +#include "swift/AST/Type.h" + +namespace swift { + +/// A small structure describing the async convention of a foreign declaration. +class ForeignAsyncConvention { + /// The index of the completion handler parameters. + unsigned CompletionHandlerParamIndex; + + /// When non-zero, indicates which parameter to the completion handler is the + /// Error? parameter (minus one) that makes this async function also throwing. + unsigned CompletionHandlerErrorParamIndex; +public: + ForeignAsyncConvention() + : CompletionHandlerParamIndex(0), CompletionHandlerErrorParamIndex(0) { } + + ForeignAsyncConvention(unsigned completionHandlerParamIndex, + Optional completionHandlerErrorParamIndex) + : CompletionHandlerParamIndex(completionHandlerParamIndex), + CompletionHandlerErrorParamIndex( + completionHandlerErrorParamIndex + ? *completionHandlerErrorParamIndex + 1 + : 0) {} + + /// Retrieve the index of the completion handler parameter, which will be + /// erased from the Swift signature of the imported async function. + unsigned completionHandlerParamIndex() const { + return CompletionHandlerParamIndex; + } + + /// Retrieve the index of the \c Error? parameter in the completion handler's + /// parameter list. When argument passed to this parameter is non-null, the + /// provided error will be thrown by the async function. + Optional completionHandlerErrorParamIndex() const { + if (CompletionHandlerErrorParamIndex == 0) + return None; + + return CompletionHandlerErrorParamIndex - 1; + } + + /// Whether the async function is throwing due to the completion handler + /// having an \c Error? parameter. + /// + /// Equivalent to \c static_cast(completionHandlerErrorParamIndex()). + bool isThrowing() const { + return CompletionHandlerErrorParamIndex != 0; + } + + bool operator==(ForeignAsyncConvention other) const { + return CompletionHandlerParamIndex == other.CompletionHandlerParamIndex + && CompletionHandlerErrorParamIndex == + other.CompletionHandlerErrorParamIndex; + } + bool operator!=(ForeignAsyncConvention other) const { + return !(*this == other); + } +}; + +} + +#endif diff --git a/include/swift/AST/ForeignErrorConvention.h b/include/swift/AST/ForeignErrorConvention.h index 48d65d4612856..d09a7a80c0d86 100644 --- a/include/swift/AST/ForeignErrorConvention.h +++ b/include/swift/AST/ForeignErrorConvention.h @@ -81,6 +81,10 @@ class ForeignErrorConvention { } Info() = default; + + Kind getKind() const { + return static_cast(TheKind); + } }; private: @@ -178,11 +182,24 @@ class ForeignErrorConvention { /// Returns the physical result type of the function, for functions /// that completely erase this information. CanType getResultType() const { - assert(getKind() == ZeroResult || - getKind() == NonZeroResult); + assert(resultTypeErasedToVoid(getKind())); return ResultType; } - + + /// Whether this kind of error import erases the result type to 'Void'. + static bool resultTypeErasedToVoid(Kind kind) { + switch (kind) { + case ZeroResult: + case NonZeroResult: + return true; + + case ZeroPreservedResult: + case NilResult: + case NonNilError: + return false; + } + } + bool operator==(ForeignErrorConvention other) const { return info.TheKind == other.info.TheKind && info.ErrorIsOwned == other.info.ErrorIsOwned diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 633527ccf7735..e4f59973c6a07 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -18,6 +18,7 @@ #include "ClangTypeConverter.h" #include "ForeignRepresentationInfo.h" #include "SubstitutionMapStorage.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DiagnosticEngine.h" @@ -281,6 +282,10 @@ struct ASTContext::Implementation { llvm::DenseMap ForeignErrorConventions; + /// Map from declarations to foreign async conventions. + llvm::DenseMap ForeignAsyncConventions; + /// Cache of previously looked-up precedence queries. AssociativityCacheType AssociativityCache; @@ -2238,6 +2243,24 @@ AbstractFunctionDecl::getForeignErrorConvention() const { return it->second; } +void AbstractFunctionDecl::setForeignAsyncConvention( + const ForeignAsyncConvention &conv) { + assert(hasAsync() && "setting error convention on non-throwing decl"); + auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions; + assert(!conventionsMap.count(this) && "error convention already set"); + conventionsMap.insert({this, conv}); +} + +Optional +AbstractFunctionDecl::getForeignAsyncConvention() const { + if (!hasAsync()) + return None; + auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions; + auto it = conventionsMap.find(this); + if (it == conventionsMap.end()) return None; + return it->second; +} + Optional swift::getKnownFoundationEntity(StringRef name){ return llvm::StringSwitch>(name) #define FOUNDATION_ENTITY(Name) .Case(#Name, KnownFoundationEntity::Name) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4fdb7199e4ba3..f1f17cbf3c042 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7255,13 +7255,14 @@ FuncDecl *FuncDecl::createImplicit(ASTContext &Context, FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc, DeclName Name, SourceLoc NameLoc, - bool Throws, ParameterList *BodyParams, + bool Async, bool Throws, + ParameterList *BodyParams, Type FnRetType, DeclContext *Parent, ClangNode ClangN) { assert(ClangN && FnRetType); auto *const FD = FuncDecl::createImpl( Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc, - /*Async=*/false, SourceLoc(), Throws, SourceLoc(), + Async, SourceLoc(), Throws, SourceLoc(), /*GenericParams=*/nullptr, Parent, ClangN); FD->setParameters(BodyParams); FD->setResultInterfaceType(FnRetType); diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 74a7e4f17fe8e..e1f1ad590b202 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3681,6 +3681,7 @@ void ClangImporter::Implementation::lookupValue( clangDecl->getMostRecentDecl(); CurrentVersion.forEachOtherImportNameVersion( + SwiftContext.LangOpts.EnableExperimentalConcurrency, [&](ImportNameVersion nameVersion) { if (anyMatching) return; @@ -3690,6 +3691,12 @@ void ClangImporter::Implementation::lookupValue( if (!newName.getDeclName().matchesRef(name)) return; + // If we asked for an async import and didn't find one, skip this. + // This filters out duplicates. + if (nameVersion.supportsConcurrency() && + !newName.getAsyncInfo()) + return; + const clang::DeclContext *clangDC = newName.getEffectiveContext().getAsDeclContext(); if (!clangDC || !clangDC->isFileContext()) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 21488368a4dbe..52f26c7d0eaaf 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -160,6 +160,7 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, DeclName name, SourceLoc nameLoc, ParameterList *bodyParams, Type resultTy, + bool async, bool throws, DeclContext *dc, ClangNode clangNode) { @@ -176,7 +177,7 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, bodyParams, resultTy, dc, clangNode); } else { - return FuncDecl::createImported(ctx, funcLoc, name, nameLoc, throws, + return FuncDecl::createImported(ctx, funcLoc, name, nameLoc, async, throws, bodyParams, resultTy, dc, clangNode); } } @@ -2254,7 +2255,7 @@ namespace { /// Whether the names we're importing are from the language version the user /// requested, or if these are decls from another version bool isActiveSwiftVersion() const { - return getVersion() == getActiveSwiftVersion(); + return getVersion().withConcurrency(false) == getActiveSwiftVersion().withConcurrency(false); } void recordMemberInContext(const DeclContext *dc, ValueDecl *member) { @@ -2300,7 +2301,7 @@ namespace { return canonicalName; } - // Special handling when we import using the older Swift name. + // Special handling when we import using the alternate Swift name. // // Import using the alternate Swift name. If that fails, or if it's // identical to the active Swift name, we won't introduce an alternate @@ -2309,6 +2310,19 @@ namespace { if (!alternateName) return ImportedName(); + // Importing for concurrency is special in that the same declaration + // is imported both with a completion handler parameter and as 'async', + // creating two separate declarations. + if (getVersion().supportsConcurrency()) { + // If the resulting name isn't special for concurrency, it's not + // different. + if (!alternateName.getAsyncInfo()) + return ImportedName(); + + // Otherwise, it's a legitimately different import. + return alternateName; + } + if (alternateName.getDeclName() == canonicalName.getDeclName() && alternateName.getEffectiveContext().equalsWithoutResolving( canonicalName.getEffectiveContext())) { @@ -2470,6 +2484,13 @@ namespace { return; } + // If this the active and current Swift versions differ based on + // concurrency, it's not actually a variant. + if (getVersion().supportsConcurrency() != + getActiveSwiftVersion().supportsConcurrency()) { + return; + } + // TODO: some versions should be deprecated instead of unavailable ASTContext &ctx = decl->getASTContext(); @@ -3837,9 +3858,10 @@ namespace { // FIXME: Poor location info. auto nameLoc = Impl.importSourceLoc(decl->getLocation()); - result = createFuncOrAccessor(Impl.SwiftContext, loc, accessorInfo, name, - nameLoc, bodyParams, resultTy, - /*throws*/ false, dc, decl); + result = createFuncOrAccessor( + Impl.SwiftContext, loc, accessorInfo, name, + nameLoc, bodyParams, resultTy, + /*async*/ false, /*throws*/ false, dc, decl); if (!dc->isModuleScopeContext()) { if (selfIsInOut) @@ -4410,6 +4432,16 @@ namespace { } } + // Determine whether the function is throwing and/or async. + bool throws = importedName.getErrorInfo().hasValue(); + bool async = false; + auto asyncConvention = importedName.getAsyncInfo(); + if (asyncConvention) { + async = true; + if (asyncConvention->isThrowing()) + throws = true; + } + auto resultTy = importedType.getType(); auto isIUO = importedType.isImplicitlyUnwrapped(); @@ -4439,8 +4471,7 @@ namespace { importedName.getDeclName(), /*nameLoc*/SourceLoc(), bodyParams, resultTy, - importedName.getErrorInfo().hasValue(), - dc, decl); + async, throws, dc, decl); result->setAccess(getOverridableAccessLevel(dc)); @@ -4472,6 +4503,11 @@ namespace { result->setForeignErrorConvention(*errorConvention); } + // Record the async convention. + if (asyncConvention) { + result->setForeignAsyncConvention(*asyncConvention); + } + // Handle attributes. if (decl->hasAttr() && isa(result) && @@ -4503,6 +4539,7 @@ namespace { Impl.addAlternateDecl(result, cast(imported)); } } + return result; } @@ -6443,6 +6480,7 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( return known->second; // Create the actual constructor. + assert(!importedName.getAsyncInfo()); auto result = Impl.createDeclWithClangNode( objcMethod, AccessLevel::Public, importedName.getDeclName(), /*NameLoc=*/SourceLoc(), failability, /*FailabilityLoc=*/SourceLoc(), @@ -7145,6 +7183,11 @@ void SwiftDeclConverter::importMirroredProtocolMembers( if (isa(afd)) return; + // Asynch methods are also always imported without async, so don't + // record them here. + if (afd->hasAsync()) + return; + auto objcMethod = dyn_cast_or_null(member->getClangDecl()); if (!objcMethod) diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 088b62ea3d2a6..791c695ff1b91 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1136,6 +1136,174 @@ Optional NameImporter::considerErrorImport( return None; } +/// Whether the given parameter name identifies a completion handler. +static bool isCompletionHandlerParamName(StringRef paramName) { + return paramName == "completionHandler" || paramName == "completion" || + paramName == "withCompletionHandler"; +} + +/// Whether the give base name implies that the first parameter is a completion +/// handler. +/// +/// \returns a trimmed base name when it does, \c None others +static Optional isCompletionHandlerInBaseName(StringRef basename) { + if (basename.endswith("WithCompletionHandler")) { + return basename.drop_back(strlen("WithCompletionHandler")); + } + + if (basename.endswith("WithCompletion")) { + return basename.drop_back(strlen("WithCompletion")); + } + + return None; +} + + +// Determine whether the given type is a nullable NSError type. +static bool isNullableNSErrorType( + clang::ASTContext &clangCtx, clang::QualType type) { + auto objcPtrType = type->getAs(); + if (!objcPtrType) + return false; + + auto iface = objcPtrType->getInterfaceDecl(); + if (!iface || iface->getName() != "NSError") + return false; + + // If nullability is specified, check it. + if (auto nullability = type->getNullability(clangCtx)) { + switch (translateNullability(*nullability)) { + case OTK_None: + return false; + + case OTK_ImplicitlyUnwrappedOptional: + case OTK_Optional: + return true; + } + } + + // Otherwise, assume it's nullable. + return true; +} + +Optional +NameImporter::considerAsyncImport( + const clang::ObjCMethodDecl *clangDecl, + StringRef &baseName, + SmallVectorImpl ¶mNames, + ArrayRef params, + bool isInitializer, bool hasCustomName, + Optional errorInfo) { + // If there are no unclaimed parameters, there's no . + unsigned errorParamAdjust = errorInfo ? 1 : 0; + if (params.size() - errorParamAdjust == 0) + return None; + + // If the # of parameter names doesn't line up with the # of parameters, + // bail out. There are extra C parameters on the method or a custom name + // was incorrect. + if (params.size() != paramNames.size() + errorParamAdjust) + return None; + + // The last parameter will be the completion handler for an async function. + unsigned completionHandlerParamIndex = params.size() - 1; + unsigned completionHandlerParamNameIndex = paramNames.size() - 1; + + // Determine whether the naming indicates that this is a completion + // handler. + Optional newBaseName; + if (isCompletionHandlerParamName(paramNames[completionHandlerParamNameIndex])) { + // The parameter itself has an appropriate name. + } else if (!hasCustomName && completionHandlerParamIndex == 0 && + (newBaseName = isCompletionHandlerInBaseName(baseName))) { + // The base name implies that the first parameter is a completion handler. + } else { + return None; + } + + // Used for returns once we've determined that the method cannot be + // imported as async, even though it has what looks like a completion handler + // parameter. + auto notAsync = [&](const char *reason) -> Optional { +#ifdef ASYNC_IMPORT_DEBUG + llvm::errs() << "*** failed async import: " << reason << "\n"; + clangDecl->dump(llvm::errs()); +#endif + + return None; + }; + + // Initializers cannot be 'async'. + // FIXME: We might eventually allow this. + if (isInitializer) + return notAsync("initializers cannot be async"); + + // Check whether we method has a suitable return type. + if (clangDecl->getReturnType()->isVoidType()) { + // 'void' is the common case; the method produces no synchronous result. + } else if (errorInfo && + ForeignErrorConvention::resultTypeErasedToVoid( + errorInfo->getKind())) { + // The method has been imported as throwing in a manner that erased the + // result type to Void. + } else { + return notAsync("method does not return void"); + } + + // The completion handler parameter must have block type. + auto completionHandlerParam = params[completionHandlerParamIndex]; + if (!isBlockParameter(completionHandlerParam)) + return notAsync("parameter is not a block"); + + // Dig out the function type of the completion handler's block type. + // If there is no prototype, (e.g., the completion handler is of type + // void (^)()), we cannot importer it. + auto completionHandlerFunctionType = + completionHandlerParam->getType()->castAs() + ->getPointeeType()->getAs(); + if (!completionHandlerFunctionType) + return notAsync("block parameter does not have a prototype"); + + // The completion handler parameter must itself return 'void'. + if (!completionHandlerFunctionType->getReturnType()->isVoidType()) + return notAsync("completion handler parameter does not return 'void'"); + + // Scan the parameters of the block type to look for a parameter of a + // nullable NSError type, which would indicate that the async method could + // throw. + Optional completionHandlerErrorParamIndex; + auto completionHandlerParamTypes = + completionHandlerFunctionType->getParamTypes(); + auto &clangCtx = clangDecl->getASTContext(); + for (unsigned paramIdx : indices(completionHandlerParamTypes)) { + auto paramType = completionHandlerParamTypes[paramIdx]; + + // We are only interested in nullable NSError parameters. + if (!isNullableNSErrorType(clangCtx, paramType)) + continue; + + // If this is the first nullable error parameter, note that. + if (!completionHandlerErrorParamIndex) { + completionHandlerErrorParamIndex = paramIdx; + continue; + } + + // More than one nullable NSError parameter. Don't import as throwing. + completionHandlerErrorParamIndex = None; + break; + } + + // Drop the completion handler parameter name. + paramNames.erase(paramNames.begin() + completionHandlerParamNameIndex); + + // Update the base name, if needed. + if (newBaseName && !hasCustomName) + baseName = *newBaseName; + + return ForeignAsyncConvention( + completionHandlerParamIndex, completionHandlerErrorParamIndex); +} + bool NameImporter::hasErrorMethodNameCollision( const clang::ObjCMethodDecl *method, unsigned paramIndex, StringRef suffixToStrip) { @@ -1359,6 +1527,21 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.hasErrorInfo = true; result.info.errorInfo = *errorInfo; } + + if (version.supportsConcurrency()) { + if (auto asyncInfo = considerAsyncImport( + method, parsedName.BaseName, parsedName.ArgumentLabels, + params, isInitializer, /*hasCustomName=*/true, + result.getErrorInfo())) { + result.info.hasAsyncInfo = true; + result.info.asyncInfo = *asyncInfo; + + // Update the name to reflect the new parameter labels. + result.declName = formDeclName( + swiftCtx, parsedName.BaseName, parsedName.ArgumentLabels, + /*isFunction=*/true, isInitializer); + } + } } return result; @@ -1604,6 +1787,16 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.errorInfo = *errorInfo; } + if (version.supportsConcurrency()) { + if (auto asyncInfo = considerAsyncImport( + objcMethod, baseName, argumentNames, params, isInitializer, + /*hasCustomName=*/false, + result.getErrorInfo())) { + result.info.hasAsyncInfo = true; + result.info.asyncInfo = *asyncInfo; + } + } + isFunction = true; // Is this one of the accessors for subscripts? @@ -1892,6 +2085,7 @@ bool NameImporter::forEachDistinctImportName( seenNames.push_back(key); activeVersion.forEachOtherImportNameVersion( + swiftCtx.LangOpts.EnableExperimentalConcurrency, [&](ImportNameVersion nameVersion) { // Check to see if the name is different. ImportedName newName = importName(decl, nameVersion); diff --git a/lib/ClangImporter/ImportName.h b/lib/ClangImporter/ImportName.h index ddb4b0aa4105c..09d90703563c9 100644 --- a/lib/ClangImporter/ImportName.h +++ b/lib/ClangImporter/ImportName.h @@ -23,6 +23,7 @@ #include "swift/Basic/Version.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "clang/Sema/Sema.h" @@ -42,15 +43,18 @@ enum { NumImportedAccessorKindBits = 3 }; /// The name version class ImportNameVersion : public RelationalOperationsBase { - unsigned rawValue; + unsigned rawValue : 31; + unsigned concurrency : 1; + friend llvm::DenseMapInfo; enum AsConstExpr_t { AsConstExpr }; - constexpr ImportNameVersion() : rawValue(0) {} + constexpr ImportNameVersion() : rawValue(0), concurrency(false) {} constexpr ImportNameVersion(unsigned version, AsConstExpr_t) - : rawValue(version) {} - explicit ImportNameVersion(unsigned version) : rawValue(version) { + : rawValue(version), concurrency(false) {} + explicit ImportNameVersion(unsigned version, bool concurrency = false) + : rawValue(version), concurrency(concurrency) { assert(version >= 2 && "only Swift 2 and later are supported"); } public: @@ -67,7 +71,7 @@ class ImportNameVersion : public RelationalOperationsBase { return ImportNameVersion::swift4_2(); } unsigned major = version[0]; - return ImportNameVersion(major >= 5 ? major + 1 : major); + return ImportNameVersion(major >= 5 ? major + 1 : major, false); } unsigned majorVersionNumber() const { @@ -89,11 +93,21 @@ class ImportNameVersion : public RelationalOperationsBase { return llvm::VersionTuple(majorVersionNumber(), minorVersionNumber()); } + /// Whether to consider importing functions as 'async'. + bool supportsConcurrency() const { return concurrency; } + + ImportNameVersion withConcurrency(bool concurrency) const { + ImportNameVersion result = *this; + result.concurrency = concurrency; + return result; + } + bool operator==(ImportNameVersion other) const { - return rawValue == other.rawValue; + return rawValue == other.rawValue && concurrency == other.concurrency; } bool operator<(ImportNameVersion other) const { - return rawValue < other.rawValue; + return rawValue < other.rawValue || + (rawValue == other.rawValue && concurrency < other.concurrency); } /// Calls \p action for each name version other than this one, first going @@ -102,10 +116,19 @@ class ImportNameVersion : public RelationalOperationsBase { /// /// This is the most useful order for importing compatibility stubs. void forEachOtherImportNameVersion( + bool withConcurrency, llvm::function_ref action) const { assert(*this >= ImportNameVersion::swift2()); ImportNameVersion nameVersion = *this; + assert(!nameVersion.supportsConcurrency()); + + // If we've been asked to also consider concurrency, do so for the + // primary version (only). + if (withConcurrency) { + action(nameVersion.withConcurrency(true)); + } + while (nameVersion > ImportNameVersion::swift2()) { --nameVersion.rawValue; action(nameVersion); @@ -175,6 +198,10 @@ class ImportedName { /// throwing Swift methods, describes how the mapping is performed. ForeignErrorConvention::Info errorInfo; + /// For names that map Objective-C completion handlers into async + /// Swift methods, describes how the mapping is performed. + ForeignAsyncConvention asyncInfo; + /// For a declaration name that makes the declaration into an /// instance member, the index of the "Self" parameter. unsigned selfIndex; @@ -201,11 +228,13 @@ class ImportedName { unsigned hasErrorInfo : 1; + unsigned hasAsyncInfo : 1; + Info() : errorInfo(), selfIndex(), initKind(CtorInitializerKind::Designated), accessorKind(ImportedAccessorKind::None), hasCustomName(false), droppedVariadic(false), importAsMember(false), hasSelfIndex(false), - hasErrorInfo(false) {} + hasErrorInfo(false), hasAsyncInfo(false) {} } info; public: @@ -239,6 +268,14 @@ class ImportedName { return None; } + /// For names that map Objective-C methods with completion handlers into + /// async Swift methods, describes how the mapping is performed. + Optional getAsyncInfo() const { + if (info.hasAsyncInfo) + return info.asyncInfo; + return None; + } + /// For a declaration name that makes the declaration into an /// instance member, the index of the "Self" parameter. Optional getSelfIndex() const { @@ -416,6 +453,14 @@ class NameImporter { ArrayRef params, bool isInitializer, bool hasCustomName); + Optional + considerAsyncImport(const clang::ObjCMethodDecl *clangDecl, + StringRef &baseName, + SmallVectorImpl ¶mNames, + ArrayRef params, + bool isInitializer, bool hasCustomName, + Optional errorInfo); + EffectiveClangContext determineEffectiveContext(const clang::NamedDecl *, const clang::DeclContext *, ImportNameVersion version); diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 69034c5c3778e..e9e0599b5f8fc 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1988,6 +1988,42 @@ static Type mapGenericArgs(const DeclContext *fromDC, return type.subst(subs); } +/// Decompose the type of a completion handler parameter in a function +/// imported as 'async' and produce the result type of the 'async' function. +static Type decomposeCompletionHandlerType( + Type paramTy, ForeignAsyncConvention info) { + auto fnType = paramTy->lookThroughAllOptionalTypes()->getAs(); + if (!fnType) + return Type(); + + SmallVector resultTypeElts; + auto params = fnType->getParams(); + for (unsigned paramIdx : indices(params)) { + const auto ¶m = params[paramIdx]; + if (param.isInOut() || param.isVariadic()) + return Type(); + + // If there is an error parameter to the completion handler, it is + // not part of the result type of the asynchronous function. + if (info.completionHandlerErrorParamIndex() && + paramIdx == *info.completionHandlerErrorParamIndex()) + continue; + + resultTypeElts.push_back(param.getPlainType()); + } + + switch (resultTypeElts.size()) { + case 0: + return paramTy->getASTContext().getVoidDecl()->getDeclaredInterfaceType(); + + case 1: + return resultTypeElts.front().getType(); + + default: + return TupleType::get(resultTypeElts, paramTy->getASTContext()); + } +} + ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( const DeclContext *dc, const clang::ObjCMethodDecl *clangDecl, ArrayRef params, bool isVariadic, @@ -2024,6 +2060,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( CanType origSwiftResultTy; Optional errorInfo = importedName.getErrorInfo(); + auto asyncInfo = importedName.getAsyncInfo(); OptionalTypeKind OptionalityOfReturn; if (clangDecl->hasAttr()) { OptionalityOfReturn = OTK_None; @@ -2122,6 +2159,9 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( continue; } + bool paramIsCompletionHandler = + asyncInfo && paramIndex == asyncInfo->completionHandlerParamIndex(); + // Import the parameter type into Swift. // Check nullability of the parameter. @@ -2191,6 +2231,21 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( continue; } + // If this is a completion handler, figure out it's effect on the result + // type but don't build it into the parameter type. + if (paramIsCompletionHandler) { + if (Type replacedSwiftResultTy = + decomposeCompletionHandlerType(swiftParamTy, *asyncInfo)) { + swiftResultTy = replacedSwiftResultTy; + + // FIXME: We will need an equivalent to "error parameter is replaced" + // for asynchronous functions. Perhaps add "async: ()"? + continue; + } + + llvm_unreachable("async info computed incorrectly?"); + } + // Map __attribute__((noescape)) to @noescape. bool addNoEscapeAttr = false; if (param->hasAttr()) { diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 3ac0d0fe45d0c..6653b2d0ee38d 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1857,6 +1857,7 @@ SwiftNameLookupExtension::hashExtension(llvm::hash_code code) const { SWIFT_LOOKUP_TABLE_VERSION_MAJOR, SWIFT_LOOKUP_TABLE_VERSION_MINOR, inferImportAsMember, + swiftCtx.LangOpts.EnableExperimentalConcurrency, version::getSwiftFullVersion()); } diff --git a/test/ClangImporter/objc_async.swift b/test/ClangImporter/objc_async.swift new file mode 100644 index 0000000000000..8ec33ae643905 --- /dev/null +++ b/test/ClangImporter/objc_async.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules -enable-experimental-concurrency %s -verify + +// REQUIRES: objc_interop +import Foundation +import ObjCConcurrency + +func testSlowServer(slowServer: SlowServer) async { + let _: Int = await slowServer.doSomethingSlow("mail") + let _: Bool = await slowServer.checkAvailability() + let _: String = await slowServer.findAnswer() ?? "nope" + let _: String = await slowServer.findAnswerFailingly() ?? "nope" + // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} + // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} +} + +func testSlowServerOldSchool(slowServer: SlowServer) { + var i1: Int = 0 + slowServer.doSomethingSlow("mail") { i in + i1 = i + } + print(i1) +} diff --git a/test/IDE/print_clang_objc_async.swift b/test/IDE/print_clang_objc_async.swift new file mode 100644 index 0000000000000..6e4539de8825c --- /dev/null +++ b/test/IDE/print_clang_objc_async.swift @@ -0,0 +1,19 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -print-module -source-filename %s -module-to-print=ObjCConcurrency -function-definitions=false -enable-experimental-concurrency > %t/ObjCConcurrency.printed.txt +// RUN: %FileCheck -input-file %t/ObjCConcurrency.printed.txt %s + +// REQUIRES: objc_interop + +// CHECK-LABEL: class SlowServer : NSObject { +// CHECK-DAG: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void) +// CHECK-DAG: func doSomethingSlow(_ operation: String) async -> Int +// CHECK-DAG: func doSomethingDangerous(_ operation: String, completionHandler handler: ((String?, Error?) -> Void)? = nil) +// CHECK-DAG: func doSomethingDangerous(_ operation: String) async throws -> String? +// CHECK-DAG: func checkAvailability(completionHandler: @escaping (Bool) -> Void) +// CHECK-DAG: func checkAvailability() async -> Bool +// CHECK-DAG: func findAnswer(completionHandler handler: @escaping (String?, Error?) -> Void) +// CHECK-DAG: func findAnswer() async throws -> String? +// CHECK-DAG: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws +// CHECK-DAG: func findAnswerFailingly() async throws -> String? +// CHECK: {{^[}]$}} diff --git a/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h new file mode 100644 index 0000000000000..9903bd0a91a64 --- /dev/null +++ b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h @@ -0,0 +1,14 @@ +@import Foundation; +@import ctypes; + +#pragma clang assume_nonnull begin + +@interface SlowServer : NSObject +-(void)doSomethingSlow:(NSString *)operation completionHandler:(void (^)(NSInteger))handler; +-(void)doSomethingDangerous:(NSString *)operation completionHandler:(void (^ _Nullable)(NSString *_Nullable, NSError * _Nullable))handler; +-(void)checkAvailabilityWithCompletionHandler:(void (^)(BOOL isAvailable))completionHandler; +-(void)findAnswerAsynchronously:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswer(completionHandler:)"))); +-(BOOL)findAnswerFailinglyWithError:(NSError * _Nullable * _Nullable)error completion:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswerFailingly(completionHandler:)"))); +@end + +#pragma clang assume_nonnull end diff --git a/test/Inputs/clang-importer-sdk/usr/include/module.map b/test/Inputs/clang-importer-sdk/usr/include/module.map index 61b062ab524eb..366101cbbb723 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/module.map +++ b/test/Inputs/clang-importer-sdk/usr/include/module.map @@ -136,3 +136,8 @@ module WinBOOL { header "winbool.h" export * } + +module ObjCConcurrency { + header "ObjCConcurrency.h" + export * +} \ No newline at end of file diff --git a/utils/swift-api-dump.py b/utils/swift-api-dump.py index 9022e9c89d5b2..d44b33ae19839 100755 --- a/utils/swift-api-dump.py +++ b/utils/swift-api-dump.py @@ -102,6 +102,8 @@ def create_parser(): parser.add_argument('--enable-infer-import-as-member', action='store_true', help='Infer when a global could be imported as a ' + 'member.') + parser.add_argument('--enable-experimental-concurrency', action='store_true', + help='Enable experimental concurrency model.') parser.add_argument('-swift-version', metavar='N', help='the Swift version to use') parser.add_argument('-show-overlay', action='store_true', @@ -328,6 +330,8 @@ def main(): extra_args = ['-skip-imports'] if args.enable_infer_import_as_member: extra_args = extra_args + ['-enable-infer-import-as-member'] + if args.enable_experimental_concurrency: + extra_args = extra_args + ['-enable-experimental-concurrency'] if args.swift_version: extra_args = extra_args + ['-swift-version', '%s' % args.swift_version] From 97d43ae65bee63c85d2a9b5a27ff91a05c9e7927 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 28 Aug 2020 14:54:18 +0900 Subject: [PATCH 416/663] [WASM] Fix conflict resolution --- utils/build-script-impl | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/build-script-impl b/utils/build-script-impl index 36888cb6a96bb..83c462612a8a4 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -125,6 +125,7 @@ KNOWN_SETTINGS=( ## Skip Build ... skip-build "" "set to configure as usual while skipping the build step" skip-build-android "" "set to skip building Swift stdlibs for Android" + skip-build-wasm "" "set to skip building Swift stdlibs for WebAssembly" skip-build-benchmarks "" "set to skip building Swift Benchmark Suite" skip-build-clang-tools-extra "" "set to skip building clang-tools-extra as part of llvm" skip-build-compiler-rt "" "set to skip building Compiler-RT" From 1132cda811369be9fa6d8d43d0ddbf0d00fd6fac Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 27 Aug 2020 23:00:48 -0700 Subject: [PATCH 417/663] [ownership] Move SemanticARCOpts into a separate folder in preparation for splitting into multiple small pseudo-passes. SemanticARCOpts keeps on growing with various optimizations attached to a single "optimization" manager. Move it to its own folder in prepation for splitting it into multiple different optimizations and utility files. --- lib/SILOptimizer/CMakeLists.txt | 1 + lib/SILOptimizer/SemanticARC/CMakeLists.txt | 2 + .../SemanticARCOpts.cpp | 43 ++++++++----------- lib/SILOptimizer/Transforms/CMakeLists.txt | 1 - 4 files changed, 22 insertions(+), 25 deletions(-) create mode 100644 lib/SILOptimizer/SemanticARC/CMakeLists.txt rename lib/SILOptimizer/{Transforms => SemanticARC}/SemanticARCOpts.cpp (99%) diff --git a/lib/SILOptimizer/CMakeLists.txt b/lib/SILOptimizer/CMakeLists.txt index 4bf45e0ebd8db..ec1440d2b06a1 100644 --- a/lib/SILOptimizer/CMakeLists.txt +++ b/lib/SILOptimizer/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(LoopTransforms) add_subdirectory(Mandatory) add_subdirectory(PassManager) add_subdirectory(SILCombiner) +add_subdirectory(SemanticARC) add_subdirectory(Transforms) add_subdirectory(UtilityPasses) add_subdirectory(Utils) diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt new file mode 100644 index 0000000000000..7ae8f36a2bbde --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -0,0 +1,2 @@ +target_sources(swiftSILOptimizer PRIVATE + SemanticARCOpts.cpp) diff --git a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp similarity index 99% rename from lib/SILOptimizer/Transforms/SemanticARCOpts.cpp rename to lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index 743dac16eaa6b..180f3882a7807 100644 --- a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -1034,8 +1034,8 @@ struct SemanticARCOptVisitor } // end anonymous namespace static llvm::cl::opt -VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", - llvm::cl::init(false), llvm::cl::Hidden); + VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", + llvm::cl::init(false), llvm::cl::Hidden); static bool canEliminatePhi( SemanticARCOptVisitor::FrozenMultiMapRange optimizableIntroducerRange, @@ -1436,7 +1436,8 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { // are within the borrow scope. // // TODO: This needs a better name. -bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst *cvi) { +bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization( + CopyValueInst *cvi) { // For now, do not run this optimization. This is just to be careful. if (onlyGuaranteedOpts) return false; @@ -1617,7 +1618,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst /// If cvi only has destroy value users, then cvi is a dead live range. Lets /// eliminate all such dead live ranges. -bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi) { +bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue( + CopyValueInst *cvi) { // This is a cheap optimization generally. // See if we are lucky and have a simple case. @@ -1857,8 +1859,7 @@ namespace { /// written to again. In both cases, we can convert load [copy] -> load_borrow /// safely. class StorageGuaranteesLoadVisitor - : public AccessUseDefChainVisitor -{ + : public AccessUseDefChainVisitor { // The outer SemanticARCOptVisitor. SemanticARCOptVisitor &ARCOpt; @@ -1867,7 +1868,7 @@ class StorageGuaranteesLoadVisitor // The current address being visited. SILValue currentAddress; - + Optional isWritten; public: @@ -1880,11 +1881,9 @@ class StorageGuaranteesLoadVisitor currentAddress = nullptr; isWritten = written; } - - void next(SILValue address) { - currentAddress = address; - } - + + void next(SILValue address) { currentAddress = address; } + void visitNestedAccess(BeginAccessInst *access) { // First see if we have read/modify. If we do not, just look through the // nested access. @@ -1901,9 +1900,7 @@ class StorageGuaranteesLoadVisitor // scope. If so, we may be able to use a load_borrow here! SmallVector endScopeUses; transform(access->getEndAccesses(), std::back_inserter(endScopeUses), - [](EndAccessInst *eai) { - return &eai->getAllOperands()[0]; - }); + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); SmallPtrSet visitedBlocks; LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); if (!checker.validateLifetime(access, endScopeUses, @@ -1930,7 +1927,7 @@ class StorageGuaranteesLoadVisitor return answer(true); } - + void visitArgumentAccess(SILFunctionArgument *arg) { // If this load_copy is from an indirect in_guaranteed argument, then we // know for sure that it will never be written to. @@ -2007,15 +2004,15 @@ class StorageGuaranteesLoadVisitor // able to also to promote load [copy] from such args to load_borrow. return answer(true); } - + void visitGlobalAccess(SILValue global) { return answer(!AccessedStorage(global, AccessedStorage::Global) - .isLetAccess(&ARCOpt.F)); + .isLetAccess(&ARCOpt.F)); } - + void visitClassAccess(RefElementAddrInst *field) { currentAddress = nullptr; - + // We know a let property won't be written to if the base object is // guaranteed for the duration of the access. // For non-let properties conservatively assume they may be written to. @@ -2071,15 +2068,13 @@ class StorageGuaranteesLoadVisitor baseObject, endScopeInsts, liveRange.getAllConsumingUses()); return answer(foundError); } - + // TODO: Handle other access kinds? void visitBase(SILValue base, AccessedStorage::Kind kind) { return answer(true); } - void visitNonAccess(SILValue addr) { - return answer(true); - } + void visitNonAccess(SILValue addr) { return answer(true); } void visitCast(SingleValueInstruction *cast, Operand *parentAddr) { return next(parentAddr->get()); diff --git a/lib/SILOptimizer/Transforms/CMakeLists.txt b/lib/SILOptimizer/Transforms/CMakeLists.txt index c51043a1910c3..ac3718b6cf20f 100644 --- a/lib/SILOptimizer/Transforms/CMakeLists.txt +++ b/lib/SILOptimizer/Transforms/CMakeLists.txt @@ -31,7 +31,6 @@ target_sources(swiftSILOptimizer PRIVATE RedundantLoadElimination.cpp RedundantOverflowCheckRemoval.cpp ReleaseDevirtualizer.cpp - SemanticARCOpts.cpp SILCodeMotion.cpp SILLowerAggregateInstrs.cpp SILMem2Reg.cpp From 109b7b8a9b854d7482ecc14aecdda673a7ea5a4e Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Fri, 28 Aug 2020 00:09:56 -0700 Subject: [PATCH 418/663] Disable LLDB tests in nightly package preset (67923799) --- utils/build-presets.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 3a0e27830069e..0892aee12e7c8 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1313,6 +1313,8 @@ dash-dash no-assertions +# SKIP LLDB TESTS (67923799) +skip-test-lldb [preset: buildbot_osx_package,no_assertions,lto] mixin-preset=buildbot_osx_package,no_assertions From 4456632805f452038d434156e11d8ea4b21ae5dd Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 28 Aug 2020 18:47:33 +0900 Subject: [PATCH 419/663] [WASM] Skip to cross compile for arm64 --- utils/build-presets.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 8b84c5d73169d..8f87de0e8f12e 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2515,6 +2515,7 @@ swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;s llvm-install-components=clang install-swift install-prefix=/%(TOOLCHAIN_NAME)s/usr +swift-darwin-supported-archs=x86_64 [preset: webassembly-host] From c98d89543cf8732e449a47fdb87b864b7b867584 Mon Sep 17 00:00:00 2001 From: tbkka Date: Fri, 28 Aug 2020 08:44:02 -0700 Subject: [PATCH 420/663] Expanded discussion of protocol types (#33621) * AnyObject behaves as if every class type implicitly conformed to it as a protocol. * Protocols "inherit" from other protocols, and this has implications for casting to existential metatypes I also moved the Any self-conformance invariant to the self-conformance subsection and added a couple of explanatory sentences. --- docs/DynamicCasting.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md index 1ef306549a148..72b369bbb3c7c 100644 --- a/docs/DynamicCasting.md +++ b/docs/DynamicCasting.md @@ -407,9 +407,10 @@ S.self.svar // 2 ``` Invariants -* If `T` conforms to `P` and `t` is an instance of `T`, then `t is P`, and `T.self is P.Type` +* If `T` conforms to `P` and `t` is an instance of `T`, then `t is P` and `T.self is P.Type` +* If `P` is a sub-protocol of `P1` and `T` is any type, then `T.self is P.Type` implies that `T.self is P1.Type` * Since every type `T` conforms to `Any`, `T.self is Any.Type` is always true -* `Any` self-conforms: `Any.self is Any.Type == true` +* Since every class type `C` conforms to `AnyObject`, `C.self is AnyObject.Type` is always true (this includes Objective-C class types) ### Note: "Self conforming" protocols @@ -439,10 +440,14 @@ let b : MyGenericType(a) As above, since `a` has type `P`, this code is instantiating `MyGenericType` with `T = P`, which is only valid if `P` conforms to `P`. Note that any protocol that specifies static methods, static properties, associated types, or initializers cannot possibly be self-conforming. -As of Swift 5.3, there are only three kinds of self-conforming protocols: -* `Any` must be self-conforming since every `T.self` is an instance of `Any.Type` -* `Error` is a self-conforming protocol -* Objective-C protocols that have no static requirements are self-conforming +As of Swift 5.3, the only self-conforming protocols are `Any`, `Error`, and Objective-C protocols that have no static requirements. + +Invariants +* `Any` self-conforms: `Any.self is Any.Type == true` +* `Error` self-conforms: `Error.self is Error.Type == true` +* If `P` self-conforms and is a sub-protocol of `P1`, then `P.self is P1.Type == true` + +For example, the last invariant here implies that for any Objective-C protocol `OP` that has no static requirements, `OP.self is AnyObject.Type`. This follows from the fact that `OP` self-conforms and that every Objective-C protocol has `AnyObject` as an implicit parent protocol. ## CoreFoundation types From 992c3830236106cdf34550968b078c72874674bb Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 27 Aug 2020 21:42:37 +0900 Subject: [PATCH 421/663] [Serialization] Serialize hasCReferences to keep linkage hasCReferences is used to determine that the function is externally available. If a function has @_cdecl and not used from anywhere in Swift side code, it will be emitted due to its hasCReferences. But if the attribute is not restored from sib, it won't be emitted even if it's used externally. So we need to serialize the attribute. --- lib/Serialization/DeserializeSIL.cpp | 9 +++++---- lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SILFormat.h | 1 + lib/Serialization/SerializeSIL.cpp | 6 +++--- test/Serialization/cdecl_attr.swift | 12 ++++++++++++ 5 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 test/Serialization/cdecl_attr.swift diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index b2cfae7bfd405..b4c536e4f7355 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -511,14 +511,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); @@ -639,6 +639,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setOptimizationMode(OptimizationMode(optimizationMode)); fn->setAlwaysWeakImported(isWeakImported); fn->setClassSubclassScope(SubclassScope(subclassScope)); + fn->setHasCReferences(bool(hasCReferences)); llvm::VersionTuple available; DECODE_VER_TUPLE(available); @@ -2824,14 +2825,14 @@ bool SILDeserializer::hasSILFunction(StringRef Name, GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, - optimizationMode, subclassScope, effect, numSpecAttrs, + optimizationMode, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, clangOwnerID, SemanticsIDs); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 2b95150e58ff2..a3e1f36a59277 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,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 = 575; // GlobalInitOnceFunction SILFunction purpose +const uint16_t SWIFTMODULE_VERSION_MINOR = 576; // hasCReferences /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index c1178d5f551ad..696f06b0d82fa 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -281,6 +281,7 @@ namespace sil_block { BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode BCFixed<2>, // classSubclassScope + BCFixed<1>, // hasCReferences BCFixed<3>, // side effect info. BCVBR<8>, // number of specialize attributes BCFixed<1>, // has qualified ownership diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index da46d36dd1b0a..fe1c2dd967a96 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -433,9 +433,9 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.isSerialized(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), - (unsigned)F.getSpecialPurpose(), - (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), - (unsigned)F.getClassSubclassScope(), (unsigned)F.getEffectsKind(), + (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), + (unsigned)F.getOptimizationMode(), (unsigned)F.getClassSubclassScope(), + (unsigned)F.hasCReferences(), (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), (unsigned)F.isExactSelfClass(), diff --git a/test/Serialization/cdecl_attr.swift b/test/Serialization/cdecl_attr.swift new file mode 100644 index 0000000000000..aa3975a738b97 --- /dev/null +++ b/test/Serialization/cdecl_attr.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// Ensure .swift -> .ll +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s + +// Ensure .swift -> .sib -> .ll +// RUN: %target-swift-frontend -emit-sib %s -o %t/cdecl_attr.sib +// RUN: %target-swift-frontend -emit-ir %t/cdecl_attr.sib | %FileCheck %s + +// CHECK: define hidden {{.*}} @foo + +@_cdecl("foo") +func foo() {} From fd6922f92dc2a0cd6f47da0969533d30f89b186c Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Wed, 19 Aug 2020 12:30:34 -0400 Subject: [PATCH 422/663] Add error reporting when looking up types by demangled name. --- include/swift/Demangling/TypeDecoder.h | 306 ++++++++++-------- include/swift/Demangling/TypeLookupError.h | 198 ++++++++++++ include/swift/Reflection/TypeRefBuilder.h | 4 +- include/swift/Remote/MetadataReader.h | 11 +- include/swift/Runtime/Debug.h | 34 -- include/swift/Runtime/Portability.h | 39 +++ lib/AST/ASTDemangler.cpp | 11 +- lib/RemoteAST/RemoteAST.cpp | 7 +- stdlib/public/Reflection/TypeRefBuilder.cpp | 24 +- .../SwiftRemoteMirror/SwiftRemoteMirror.cpp | 2 +- .../public/runtime/CompatibilityOverride.def | 4 +- stdlib/public/runtime/Metadata.cpp | 61 ++-- stdlib/public/runtime/MetadataLookup.cpp | 255 +++++++++------ stdlib/public/runtime/Private.h | 21 +- stdlib/public/runtime/ProtocolConformance.cpp | 84 ++--- stdlib/public/runtime/ReflectionMirror.mm | 36 ++- stdlib/public/runtime/SwiftObject.mm | 3 +- stdlib/public/stubs/Assert.cpp | 1 + .../swift-reflection-dump.cpp | 11 +- unittests/runtime/CompatibilityOverride.cpp | 8 +- 20 files changed, 743 insertions(+), 377 deletions(-) create mode 100644 include/swift/Demangling/TypeLookupError.h diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index e591e978dccd1..da2ec53c6ccd4 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -18,10 +18,12 @@ #ifndef SWIFT_DEMANGLING_TYPEDECODER_H #define SWIFT_DEMANGLING_TYPEDECODER_H +#include "TypeLookupError.h" #include "swift/ABI/MetadataValues.h" +#include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangler.h" #include "swift/Demangling/NamespaceMacros.h" -#include "swift/Basic/LLVM.h" +#include "swift/Runtime/Portability.h" #include "swift/Runtime/Unreachable.h" #include "swift/Strings.h" #include "llvm/ADT/ArrayRef.h" @@ -317,6 +319,14 @@ getObjCClassOrProtocolName(NodePointer node) { } #endif +#define MAKE_NODE_TYPE_ERROR(Node, Fmt, ...) \ + TypeLookupError("TypeDecoder.h:%d: Node kind %u \"%.*s\" - " Fmt, __LINE__, \ + Node->getKind(), \ + Node->hasText() ? (int)Node->getText().size() : 0, \ + Node->hasText() ? Node->getText().data() : "", __VA_ARGS__) + +#define MAKE_NODE_TYPE_ERROR0(Node, Str) MAKE_NODE_TYPE_ERROR(Node, "%s", Str) + /// Decode a mangled type to construct an abstract type, forming such /// types by invoking a custom builder. template @@ -333,24 +343,25 @@ class TypeDecoder { : Builder(Builder) {} /// Given a demangle tree, attempt to turn it into a type. - BuiltType decodeMangledType(NodePointer Node) { - if (!Node) return BuiltType(); + TypeLookupErrorOr decodeMangledType(NodePointer Node) { + if (!Node) + return TypeLookupError("Node is NULL"); using NodeKind = Demangle::Node::Kind; switch (Node->getKind()) { case NodeKind::Global: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::TypeMangling: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::Type: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::Class: @@ -369,8 +380,8 @@ class TypeDecoder { BuiltTypeDecl typeDecl = BuiltTypeDecl(); BuiltType parent = BuiltType(); bool typeAlias = false; - if (!decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias)) - return BuiltType(); + if (auto error = decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias)) + return *error; if (typeAlias) return Builder.createTypeAliasType(typeDecl, parent); @@ -384,19 +395,21 @@ class TypeDecoder { case NodeKind::BoundGenericTypeAlias: case NodeKind::BoundGenericOtherNominalType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); llvm::SmallVector args; const auto &genericArgs = Node->getChild(1); if (genericArgs->getKind() != NodeKind::TypeList) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList"); for (auto genericArg : *genericArgs) { auto paramType = decodeMangledType(genericArg); - if (!paramType) - return BuiltType(); - args.push_back(paramType); + if (paramType.isError()) + return paramType; + args.push_back(paramType.getType()); } auto ChildNode = Node->getChild(0); @@ -413,9 +426,9 @@ class TypeDecoder { BuiltTypeDecl typeDecl = BuiltTypeDecl(); BuiltType parent = BuiltType(); bool typeAlias = false; - if (!decodeMangledTypeDecl(ChildNode, typeDecl, - parent, typeAlias)) - return BuiltType(); + if (auto error = + decodeMangledTypeDecl(ChildNode, typeDecl, parent, typeAlias)) + return *error; return Builder.createBoundGenericType(typeDecl, args, parent); } @@ -445,11 +458,15 @@ class TypeDecoder { // But when resolving it to a type, we want to *keep* the argument // so that the parent type becomes 'S' and not 'P'. if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); const auto &genericArgs = Node->getChild(1); if (genericArgs->getNumChildren() != 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(genericArgs, + "expected 1 generic argument, saw %u", + genericArgs->getNumChildren()); return decodeMangledType(genericArgs->getChild(0)); } @@ -469,7 +486,7 @@ class TypeDecoder { auto reprNode = Node->getChild(i++); if (reprNode->getKind() != NodeKind::MetatypeRepresentation || !reprNode->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(reprNode, "wrong node kind or no text"); if (reprNode->getText() == "@thin") repr = ImplMetatypeRepresentation::Thin; else if (reprNode->getText() == "@thick") @@ -477,26 +494,28 @@ class TypeDecoder { else if (reprNode->getText() == "@objc_metatype") repr = ImplMetatypeRepresentation::ObjC; } else if (Node->getNumChildren() < 1) { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); } auto instance = decodeMangledType(Node->getChild(i)); - if (!instance) - return BuiltType(); + if (instance.isError()) + return instance; if (Node->getKind() == NodeKind::Metatype) { - return Builder.createMetatypeType(instance, repr); + return Builder.createMetatypeType(instance.getType(), repr); } else if (Node->getKind() == NodeKind::ExistentialMetatype) { - return Builder.createExistentialMetatypeType(instance, repr); + return Builder.createExistentialMetatypeType(instance.getType(), repr); } else { assert(false); - return nullptr; + return MAKE_NODE_TYPE_ERROR0(Node, + "Metatype/ExistentialMetatype Node " + "had a different kind when re-checked"); } } case NodeKind::ProtocolList: case NodeKind::ProtocolListWithAnyObject: case NodeKind::ProtocolListWithClass: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); // Find the protocol list. llvm::SmallVector Protocols; @@ -511,7 +530,8 @@ class TypeDecoder { if (auto Protocol = decodeMangledProtocolType(componentType)) Protocols.push_back(Protocol); else - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(componentType, + "failed to decode protocol type"); } // Superclass or AnyObject, if present. @@ -519,11 +539,15 @@ class TypeDecoder { auto Superclass = BuiltType(); if (Node->getKind() == NodeKind::ProtocolListWithClass) { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto superclassNode = Node->getChild(1); - Superclass = decodeMangledType(superclassNode); - if (!Superclass) return BuiltType(); + auto result = decodeMangledType(superclassNode); + if (result.isError()) + return result; + Superclass = result.getType(); IsClassBound = true; } else if (Node->getKind() == NodeKind::ProtocolListWithAnyObject) { @@ -541,17 +565,18 @@ class TypeDecoder { /*IsClassBound=*/false); } - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "failed to decode protocol type"); } case NodeKind::DynamicSelf: { if (Node->getNumChildren() != 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, "expected 1 child, saw %u", + Node->getNumChildren()); auto selfType = decodeMangledType(Node->getChild(0)); - if (!selfType) - return BuiltType(); + if (selfType.isError()) + return selfType; - return Builder.createDynamicSelfType(selfType); + return Builder.createDynamicSelfType(selfType.getType()); } case NodeKind::DependentGenericParamType: { auto depth = Node->getChild(0)->getIndex(); @@ -571,7 +596,9 @@ class TypeDecoder { case NodeKind::EscapingLinearFunctionType: case NodeKind::FunctionType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); FunctionTypeFlags flags; if (Node->getKind() == NodeKind::ObjCBlock || @@ -611,13 +638,16 @@ class TypeDecoder { flags = flags.withAsync(isAsync).withThrows(isThrow); if (Node->getNumChildren() < firstChildIdx + 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (%u)", + Node->getNumChildren(), firstChildIdx + 2); bool hasParamFlags = false; llvm::SmallVector, 8> parameters; if (!decodeMangledFunctionInputType(Node->getChild(firstChildIdx), parameters, hasParamFlags)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node->getChild(firstChildIdx), + "failed to decode function type"); flags = flags.withNumParameters(parameters.size()) .withParameterFlags(hasParamFlags) @@ -631,8 +661,9 @@ class TypeDecoder { NodeKind::EscapingLinearFunctionType); auto result = decodeMangledType(Node->getChild(firstChildIdx+1)); - if (!result) return BuiltType(); - return Builder.createFunctionType(parameters, result, flags); + if (result.isError()) + return result; + return Builder.createFunctionType(parameters, result.getType(), flags); } case NodeKind::ImplFunctionType: { auto calleeConvention = ImplParameterConvention::Direct_Unowned; @@ -646,7 +677,7 @@ class TypeDecoder { if (child->getKind() == NodeKind::ImplConvention) { if (!child->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "expected text"); if (child->getText() == "@convention(thin)") { flags = @@ -656,7 +687,7 @@ class TypeDecoder { } } else if (child->getKind() == NodeKind::ImplFunctionAttribute) { if (!child->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "expected text"); StringRef text = child->getText(); if (text == "@convention(c)") { @@ -676,15 +707,18 @@ class TypeDecoder { flags = flags.withEscaping(); } else if (child->getKind() == NodeKind::ImplParameter) { if (decodeImplFunctionParam(child, parameters)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function parameter"); } else if (child->getKind() == NodeKind::ImplResult) { if (decodeImplFunctionParam(child, results)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function parameter"); } else if (child->getKind() == NodeKind::ImplErrorResult) { if (decodeImplFunctionPart(child, errorResults)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function part"); } else { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "unexpected kind"); } } @@ -696,7 +730,8 @@ class TypeDecoder { errorResult = errorResults.front(); break; default: - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, "got %zu errors", + errorResults.size()); } // TODO: Some cases not handled above, but *probably* they cannot @@ -711,13 +746,13 @@ class TypeDecoder { case NodeKind::ArgumentTuple: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); return decodeMangledType(Node->getChild(0)); case NodeKind::ReturnType: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); return decodeMangledType(Node->getChild(0)); @@ -726,12 +761,13 @@ class TypeDecoder { std::string labels; for (auto &element : *Node) { if (element->getKind() != NodeKind::TupleElement) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind"); // If the tuple element is labeled, add its label to 'labels'. unsigned typeChildIndex = 0; if (element->getChild(typeChildIndex)->getKind() == NodeKind::VariadicMarker) { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(element->getChild(typeChildIndex), + "no children"); } if (element->getChild(typeChildIndex)->getKind() == NodeKind::TupleElementName) { // Add spaces to terminate all the previous labels if this @@ -749,22 +785,23 @@ class TypeDecoder { } // Decode the element type. - BuiltType elementType = - decodeMangledType(element->getChild(typeChildIndex)); - if (!elementType) - return BuiltType(); + auto elementType = decodeMangledType(element->getChild(typeChildIndex)); + if (elementType.isError()) + return elementType; - elements.push_back(elementType); + elements.push_back(elementType.getType()); } return Builder.createTupleType(elements, std::move(labels)); } case NodeKind::TupleElement: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); if (Node->getChild(0)->getKind() == NodeKind::TupleElementName) { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } @@ -772,68 +809,75 @@ class TypeDecoder { case NodeKind::DependentGenericType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } case NodeKind::DependentMemberType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; auto assocTypeChild = Node->getChild(1); auto member = assocTypeChild->getFirstChild()->getText(); if (assocTypeChild->getNumChildren() < 2) - return Builder.createDependentMemberType(member.str(), base); + return Builder.createDependentMemberType(member.str(), base.getType()); auto protocol = decodeMangledProtocolType(assocTypeChild->getChild(1)); if (!protocol) return BuiltType(); - return Builder.createDependentMemberType(member.str(), base, protocol); + return Builder.createDependentMemberType(member.str(), base.getType(), + protocol); } case NodeKind::DependentAssociatedTypeRef: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } case NodeKind::Unowned: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createUnownedStorageType(base); + if (base.isError()) + return base; + return Builder.createUnownedStorageType(base.getType()); } case NodeKind::Unmanaged: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createUnmanagedStorageType(base); + if (base.isError()) + return base; + return Builder.createUnmanagedStorageType(base.getType()); } case NodeKind::Weak: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createWeakStorageType(base); + if (base.isError()) + return base; + return Builder.createWeakStorageType(base.getType()); } case NodeKind::SILBoxType: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createSILBoxType(base); + if (base.isError()) + return base; + return Builder.createSILBoxType(base.getType()); } case NodeKind::SILBoxTypeWithLayout: { // TODO: Implement SILBoxTypeRefs with layout. As a stopgap, specify the @@ -842,57 +886,62 @@ class TypeDecoder { } case NodeKind::SugaredOptional: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createOptionalType(base); + return Builder.createOptionalType(base.getType()); } case NodeKind::SugaredArray: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createArrayType(base); + return Builder.createArrayType(base.getType()); } case NodeKind::SugaredDictionary: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto key = decodeMangledType(Node->getChild(0)); - if (!key) - return BuiltType(); + if (key.isError()) + return key; auto value = decodeMangledType(Node->getChild(1)); - if (!key) - return BuiltType(); + if (value.isError()) + return value; - return Builder.createDictionaryType(key, value); + return Builder.createDictionaryType(key.getType(), value.getType()); } case NodeKind::SugaredParen: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createParenType(base); + return Builder.createParenType(base.getType()); } case NodeKind::OpaqueType: { if (Node->getNumChildren() < 3) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (3)", + Node->getNumChildren()); auto descriptor = Node->getChild(0); auto ordinalNode = Node->getChild(1); if (ordinalNode->getKind() != NodeKind::Index || !ordinalNode->hasIndex()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(ordinalNode, + "unexpected kind or no index"); auto ordinal = ordinalNode->getIndex(); std::vector genericArgsBuf; @@ -905,9 +954,9 @@ class TypeDecoder { break; for (auto argNode : *genericsNode) { auto arg = decodeMangledType(argNode); - if (!arg) - return BuiltType(); - genericArgsBuf.push_back(arg); + if (arg.isError()) + return arg; + genericArgsBuf.push_back(arg.getType()); } } genericArgsLevels.push_back(genericArgsBuf.size()); @@ -923,7 +972,7 @@ class TypeDecoder { // TODO: Handle OpaqueReturnType, when we're in the middle of reconstructing // the defining decl default: - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind"); } } @@ -943,11 +992,11 @@ class TypeDecoder { T::getConventionFromString(conventionString); if (!convention) return true; - BuiltType type = decodeMangledType(node->getChild(1)); - if (!type) + auto type = decodeMangledType(node->getChild(1)); + if (type.isError()) return true; - results.emplace_back(type, *convention); + results.emplace_back(type.getType(), *convention); return false; } @@ -968,8 +1017,8 @@ class TypeDecoder { auto convention = T::getConventionFromString(conventionString); if (!convention) return true; - BuiltType type = decodeMangledType(typeNode); - if (!type) + auto result = decodeMangledType(typeNode); + if (result.isError()) return true; auto diffKind = T::DifferentiabilityType::DifferentiableOrNotApplicable; @@ -984,14 +1033,13 @@ class TypeDecoder { diffKind = *optDiffKind; } - results.emplace_back(type, *convention, diffKind); + results.emplace_back(result.getType(), *convention, diffKind); return false; } - bool decodeMangledTypeDecl(Demangle::NodePointer node, - BuiltTypeDecl &typeDecl, - BuiltType &parent, - bool &typeAlias) { + llvm::Optional + decodeMangledTypeDecl(Demangle::NodePointer node, BuiltTypeDecl &typeDecl, + BuiltType &parent, bool &typeAlias) { if (node->getKind() == NodeKind::Type) return decodeMangledTypeDecl(node->getChild(0), typeDecl, parent, typeAlias); @@ -1002,7 +1050,9 @@ class TypeDecoder { declNode = node; } else { if (node->getNumChildren() < 2) - return false; + return MAKE_NODE_TYPE_ERROR( + node, "Number of node children (%u) less than required (2)", + node->getNumChildren()); auto parentContext = node->getChild(0); @@ -1018,11 +1068,14 @@ class TypeDecoder { case Node::Kind::Extension: // Decode the type being extended. if (parentContext->getNumChildren() < 2) - return false; + return MAKE_NODE_TYPE_ERROR(parentContext, + "Number of parentContext children (%u) " + "less than required (2)", + node->getNumChildren()); parentContext = parentContext->getChild(1); LLVM_FALLTHROUGH; default: - parent = decodeMangledType(parentContext); + parent = decodeMangledType(parentContext).getType(); // Remove any generic arguments from the context node, producing a // node that references the nominal type declaration. declNode = Demangle::getUnspecialized(node, Builder.getNodeFactory()); @@ -1030,9 +1083,10 @@ class TypeDecoder { } } typeDecl = Builder.createTypeDecl(declNode, typeAlias); - if (!typeDecl) return false; + if (!typeDecl) + return TypeLookupError("Failed to create type decl"); - return true; + return llvm::None; } BuiltProtocolDecl decodeMangledProtocolType(Demangle::NodePointer node) { @@ -1097,10 +1151,10 @@ class TypeDecoder { } auto paramType = decodeMangledType(node); - if (!paramType) + if (paramType.isError()) return false; - param.setType(paramType); + param.setType(paramType.getType()); return true; }; @@ -1158,14 +1212,12 @@ class TypeDecoder { } }; -template -inline typename BuilderType::BuiltType -decodeMangledType(BuilderType &Builder, - NodePointer Node) { +template +inline TypeLookupErrorOr +decodeMangledType(BuilderType &Builder, NodePointer Node) { return TypeDecoder(Builder).decodeMangledType(Node); } - SWIFT_END_INLINE_NAMESPACE } // end namespace Demangle } // end namespace swift diff --git a/include/swift/Demangling/TypeLookupError.h b/include/swift/Demangling/TypeLookupError.h new file mode 100644 index 0000000000000..c67fc35598be8 --- /dev/null +++ b/include/swift/Demangling/TypeLookupError.h @@ -0,0 +1,198 @@ +//===--- TypeLookupError.h - Type lookup error value. -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Provides the TypeLookupError class, which represents errors when demangling +// or looking up types. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_DEMANGLING_TypeLookupError_H +#define SWIFT_DEMANGLING_TypeLookupError_H + +#include "swift/Basic/TaggedUnion.h" +#include "swift/Runtime/Portability.h" + +namespace swift { + +/// An error that occurred while looking up a type at runtime from a mangled +/// name. +/// /// +/// This ultimately just provides a string, but is built to take up minimal +/// space when passed around, and perform as much work lazily as possible. We +/// don't want to spend a lot of time building strings when the caller is going +/// to handle the error gracefully and try a fallback. We only want to waste +/// time/space on that when the error message is actually relevant, so build it +/// as late as possible. +/// /// +/// To be as compact as possible, this type holds a context pointer and a +/// callback function. The callback function uses the context pointer to return +/// an error string when requested. The callback function also does quadruple +/// duty to copy/destroy the context as needed, and free the returned error +/// string if needed. Commands are passed to the callback to request the +/// different operations, which means we only have to store one function pointer +/// instead of four. +class TypeLookupError { +public: + /// The commands that can be passed to the callback function. + enum class Command { + /// Return the error string to the caller, as a char *. + CopyErrorString, + + /// Destroy the error string returned from CopyErrorString, if necessary. + /// The return value is ignored. + DestroyErrorString, + + /// Return a copy of the context pointer (used for copying TypeLookupError + /// objects.) + CopyContext, + + /// Destroy the context pointer. The return value is ignored. + DestroyContext, + }; + + /// The callback used to respond to the commands. The parameters are: + /// - `context`: the context that the value was initialized with, or the + /// context returned from a CopyContext call + /// - `command`: the command to respond to + /// - `param`: when `command` is `DestroyErrorString`, the string pointer to + /// destroy, otherwise NULL + using Callback = void *(*)(void *context, Command command, void *param); + +private: + void *Context; + Callback Fn; + + /// A no-op callback used to avoid a bunch of `if (Fn)` checks. + static void *nop(void *context, Command command, void *param) { + return nullptr; + } + + /// Helper functions for getting a C string from a lambda. These allow us to + /// wrap lambdas returning `char *` or `std::string` and standardize them on + /// `char *`. + static char *getCString(char *str) { return str; } + + static char *getCString(const std::string &str) { + return strdup(str.c_str()); + } + +public: + TypeLookupError(const TypeLookupError &other) { + Fn = other.Fn; + Context = other.Fn(other.Context, Command::CopyContext, nullptr); + } + + TypeLookupError(TypeLookupError &&other) { + Fn = other.Fn; + Context = other.Context; + + other.Fn = nop; + other.Context = nullptr; + } + + ~TypeLookupError() { Fn(Context, Command::DestroyContext, nullptr); } + + TypeLookupError(void *context, Callback fn) : Context(context), Fn(fn ? fn : nop) {} + + TypeLookupError &operator=(const TypeLookupError &other) { + if (this == &other) + return *this; + + Fn(Context, Command::DestroyContext, nullptr); + Fn = other.Fn; + Context = Fn(Context, Command::CopyContext, nullptr); + + return *this; + } + + /// Construct a TypeLookupError that just returns a constant C string. + TypeLookupError(const char *str) + : TypeLookupError([=] { return const_cast(str); }) {} + + /// Construct a TypeLookupError that creates a string using asprintf. The passed-in + /// format string and arguments are passed directly to swift_asprintf when + /// the string is requested. The arguments are captured and the string is only + /// formatted when needed. + template + TypeLookupError(const char *fmt, Args... args) + : TypeLookupError([=] { + char *str; + swift_asprintf(&str, fmt, args...); + return str; + }) {} + + /// Construct a TypeLookupError that wraps a function returning a string. The + /// passed-in function can return either a `std::string` or `char *`. If it + /// returns `char *` then the string will be destroyed with `free()`. + template TypeLookupError(const F &fn) { + Context = new F(fn); + Fn = [](void *context, Command command, void *param) -> void * { + auto castContext = reinterpret_cast(context); + switch (command) { + case Command::CopyErrorString: { + return TypeLookupError::getCString((*castContext)()); + } + case Command::DestroyErrorString: + free(param); + return nullptr; + case Command::CopyContext: + return new F(*castContext); + case Command::DestroyContext: + delete castContext; + return nullptr; + } + }; + } + + /// Get the error string from the error value. The value must be passed to + /// `freeErrorString` when done. (Unless you're just calling a `fatalError` + /// in which case there's no point.) + char *copyErrorString() { + return reinterpret_cast( + Fn(Context, Command::CopyErrorString, nullptr)); + } + + /// Free an error string previously obtained from `copyErrorString`. + void freeErrorString(char *str) { + Fn(Context, Command::DestroyErrorString, str); + } +}; + +/// A value that's either a `TypeLookupError` or some parameterized type value `T`. A +/// convenience wrapper around `TaggedUnion`. +template class TypeLookupErrorOr { + TaggedUnion Value; + +public: + TypeLookupErrorOr(const T &t) : Value(t) { + if (!t) + Value = TypeLookupError("unknown error"); + } + + TypeLookupErrorOr(const TypeLookupError &te) : Value(te) {} + + T getType() { + if (auto *ptr = Value.template dyn_cast()) + return *ptr; + return T(); + } + + TypeLookupError *getError() { + return Value.template dyn_cast(); + } + + bool isError() { return getError() != nullptr; } +}; + +} // namespace swift + +#endif // SWIFT_DEMANGLING_TypeLookupError_H diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index f375918a5ff5d..3914810cbfd8f 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -618,8 +618,8 @@ class TypeRefBuilder { }), OpaqueUnderlyingTypeReader( [&reader](uint64_t descriptorAddr, unsigned ordinal) -> const TypeRef* { - return reader.readUnderlyingTypeForOpaqueTypeDescriptor(descriptorAddr, - ordinal); + return reader.readUnderlyingTypeForOpaqueTypeDescriptor( + descriptorAddr, ordinal).getType(); }) {} diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 4450066283afc..0090ae0746ed6 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -463,7 +463,8 @@ class MetadataReader { } /// Given a demangle tree, attempt to turn it into a type. - BuiltType decodeMangledType(NodePointer Node) { + TypeLookupErrorOr + decodeMangledType(NodePointer Node) { return swift::Demangle::decodeMangledType(Builder, Node); } @@ -925,8 +926,8 @@ class MetadataReader { swift_runtime_unreachable("Unhandled MetadataKind in switch"); } - BuiltType readTypeFromMangledName(const char *MangledTypeName, - size_t Length) { + TypeLookupErrorOr + readTypeFromMangledName(const char *MangledTypeName, size_t Length) { Demangle::Demangler Dem; Demangle::NodePointer Demangled = Dem.demangleSymbol(StringRef(MangledTypeName, Length)); @@ -1183,14 +1184,14 @@ class MetadataReader { MangledNameKind::Type, Dem); } - BuiltType + TypeLookupErrorOr readUnderlyingTypeForOpaqueTypeDescriptor(StoredPointer contextAddr, unsigned ordinal) { Demangle::Demangler Dem; auto node = readUnderlyingTypeManglingForOpaqueTypeDescriptor(contextAddr, ordinal, Dem); if (!node) - return BuiltType(); + return TypeLookupError("Failed to read type mangling for descriptor."); return decodeMangledType(node); } diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h index 86e19642e51a7..f14e8d16f1554 100644 --- a/include/swift/Runtime/Debug.h +++ b/include/swift/Runtime/Debug.h @@ -21,7 +21,6 @@ #include "swift/Runtime/Unreachable.h" #include #include -#include #include #include @@ -248,39 +247,6 @@ std::atomic _swift_debug_metadataAllocationBacktraceList; SWIFT_RUNTIME_STDLIB_SPI const void * const _swift_debug_protocolConformanceStatePointer; -SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE -inline static int swift_asprintf(char **strp, const char *fmt, ...) { - va_list args; - va_start(args, fmt); -#if defined(_WIN32) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuninitialized" - int len = _vscprintf(fmt, args); -#pragma GCC diagnostic pop - if (len < 0) { - va_end(args); - return -1; - } - char *buffer = static_cast(malloc(len + 1)); - if (!buffer) { - va_end(args); - return -1; - } - int result = vsprintf(buffer, fmt, args); - if (result < 0) { - va_end(args); - free(buffer); - return -1; - } - *strp = buffer; -#else - int result = vasprintf(strp, fmt, args); -#endif - va_end(args); - return result; -} - - // namespace swift } diff --git a/include/swift/Runtime/Portability.h b/include/swift/Runtime/Portability.h index 9e4fc418e162f..cd19b2c4193ba 100644 --- a/include/swift/Runtime/Portability.h +++ b/include/swift/Runtime/Portability.h @@ -16,8 +16,47 @@ #ifndef SWIFT_RUNTIME_PORTABILITY_H #define SWIFT_RUNTIME_PORTABILITY_H + +#include #include +#include +#include size_t _swift_strlcpy(char *dst, const char *src, size_t maxlen); +// Skip the attribute when included by the compiler. +#ifdef SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +#endif +inline static int swift_asprintf(char **strp, const char *fmt, ...) { + va_list args; + va_start(args, fmt); +#if defined(_WIN32) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + int len = _vscprintf(fmt, args); +#pragma GCC diagnostic pop + if (len < 0) { + va_end(args); + return -1; + } + char *buffer = static_cast(malloc(len + 1)); + if (!buffer) { + va_end(args); + return -1; + } + int result = vsprintf(buffer, fmt, args); + if (result < 0) { + va_end(args); + free(buffer); + return -1; + } + *strp = buffer; +#else + int result = vasprintf(strp, fmt, args); +#endif + va_end(args); + return result; +} + #endif diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 6e44fd70da0ef..b613d94f17a7d 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -44,7 +44,7 @@ Type swift::Demangle::getTypeForMangling(ASTContext &ctx, return Type(); ASTBuilder builder(ctx); - return swift::Demangle::decodeMangledType(builder, node); + return swift::Demangle::decodeMangledType(builder, node).getType(); } TypeDecl *swift::Demangle::getTypeDeclForMangling(ASTContext &ctx, @@ -847,8 +847,8 @@ CanGenericSignature ASTBuilder::demangleGenericSignature( if (child->getNumChildren() != 2) return CanGenericSignature(); - auto subjectType = swift::Demangle::decodeMangledType( - *this, child->getChild(0)); + auto subjectType = + swift::Demangle::decodeMangledType(*this, child->getChild(0)).getType(); if (!subjectType) return CanGenericSignature(); @@ -857,8 +857,9 @@ CanGenericSignature ASTBuilder::demangleGenericSignature( Demangle::Node::Kind::DependentGenericConformanceRequirement || child->getKind() == Demangle::Node::Kind::DependentGenericSameTypeRequirement) { - constraintType = swift::Demangle::decodeMangledType( - *this, child->getChild(1)); + constraintType = + swift::Demangle::decodeMangledType(*this, child->getChild(1)) + .getType(); if (!constraintType) return CanGenericSignature(); } diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp index 686a8421f642d..0f937e95cec77 100644 --- a/lib/RemoteAST/RemoteAST.cpp +++ b/lib/RemoteAST/RemoteAST.cpp @@ -632,9 +632,10 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { SubstitutionMap substitutions, unsigned ordinal) override { auto underlyingType = Reader - .readUnderlyingTypeForOpaqueTypeDescriptor(opaqueDescriptor.getAddressData(), - ordinal); - + .readUnderlyingTypeForOpaqueTypeDescriptor( + opaqueDescriptor.getAddressData(), ordinal) + .getType(); + if (!underlyingType) return getFailure(); diff --git a/stdlib/public/Reflection/TypeRefBuilder.cpp b/stdlib/public/Reflection/TypeRefBuilder.cpp index 772afeb1e98f2..d811f53d89036 100644 --- a/stdlib/public/Reflection/TypeRefBuilder.cpp +++ b/stdlib/public/Reflection/TypeRefBuilder.cpp @@ -135,7 +135,8 @@ lookupTypeWitness(const std::string &MangledTypeName, auto SubstitutedTypeName = readTypeRef(AssocTy, AssocTy->SubstitutedTypeName); auto Demangled = demangleTypeRef(SubstitutedTypeName); - auto *TypeWitness = swift::Demangle::decodeMangledType(*this, Demangled); + auto *TypeWitness = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); AssociatedTypeCache.insert(std::make_pair(key, TypeWitness)); return TypeWitness; @@ -155,7 +156,8 @@ lookupSuperclass(const TypeRef *TR) { return nullptr; auto Demangled = demangleTypeRef(readTypeRef(FD, FD->Superclass)); - auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); + auto Unsubstituted = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); if (!Unsubstituted) return nullptr; @@ -226,7 +228,8 @@ bool TypeRefBuilder::getFieldTypeRefs( } auto Demangled = demangleTypeRef(readTypeRef(Field,Field->MangledTypeName)); - auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); + auto Unsubstituted = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); if (!Unsubstituted) return false; @@ -304,7 +307,7 @@ TypeRefBuilder::getClosureContextInfo(RemoteRef CD) { if (CR->hasMangledTypeName()) { auto MangledName = readTypeRef(CR, CR->MangledTypeName); auto DemangleTree = demangleTypeRef(MangledName); - TR = swift::Demangle::decodeMangledType(*this, DemangleTree); + TR = swift::Demangle::decodeMangledType(*this, DemangleTree).getType(); } Info.CaptureTypes.push_back(TR); } @@ -316,7 +319,7 @@ TypeRefBuilder::getClosureContextInfo(RemoteRef CD) { if (MSR->hasMangledTypeName()) { auto MangledName = readTypeRef(MSR, MSR->MangledTypeName); auto DemangleTree = demangleTypeRef(MangledName); - TR = swift::Demangle::decodeMangledType(*this, DemangleTree); + TR = swift::Demangle::decodeMangledType(*this, DemangleTree).getType(); } const MetadataSource *MS = nullptr; @@ -344,12 +347,17 @@ TypeRefBuilder::dumpTypeRef(RemoteRef MangledName, auto DemangleTree = demangleTypeRef(MangledName); auto TypeName = nodeToString(DemangleTree); fprintf(file, "%s\n", TypeName.c_str()); - auto TR = swift::Demangle::decodeMangledType(*this, DemangleTree); - if (!TR) { + auto Result = swift::Demangle::decodeMangledType(*this, DemangleTree); + if (Result.isError()) { + auto *Error = Result.getError(); + char *ErrorStr = Error->copyErrorString(); auto str = getTypeRefString(MangledName); - fprintf(file, "!!! Invalid typeref: %s\n", std::string(str.begin(), str.end()).c_str()); + fprintf(file, "!!! Invalid typeref: %s - %s\n", + std::string(str.begin(), str.end()).c_str(), ErrorStr); + Error->freeErrorString(ErrorStr); return; } + auto TR = Result.getType(); TR->dump(file); fprintf(file, "\n"); } diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 114cf058512d0..eccfd625425a5 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -298,7 +298,7 @@ swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef, const char *MangledTypeName, uint64_t Length) { auto Context = ContextRef->nativeContext; - auto TR = Context->readTypeFromMangledName(MangledTypeName, Length); + auto TR = Context->readTypeFromMangledName(MangledTypeName, Length).getType(); return reinterpret_cast(TR); } diff --git a/stdlib/public/runtime/CompatibilityOverride.def b/stdlib/public/runtime/CompatibilityOverride.def index 92e32430251cd..de154bb44d50f 100644 --- a/stdlib/public/runtime/CompatibilityOverride.def +++ b/stdlib/public/runtime/CompatibilityOverride.def @@ -138,7 +138,7 @@ OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, (const void *pattern, const void *arguments), (pattern, arguments)) -OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift::, +OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, (MetadataRequest request, Demangler &demangler, Demangle::NodePointer node, @@ -146,7 +146,7 @@ OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift SubstGenericParameterFn substGenericParam, SubstDependentWitnessTableFn substWitnessTable), (request, demangler, node, arguments, substGenericParam, substWitnessTable)) -OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeInfo, , SWIFT_CC(swift), swift::, +OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, (MetadataRequest request, StringRef typeName, const void * const *arguments, diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 1dfe45dd8c62f..a8e9f2a1b81eb 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -2916,24 +2916,22 @@ getSuperclassMetadata(MetadataRequest request, const ClassMetadata *self) { StringRef superclassName = Demangle::makeSymbolicMangledNameStringRef(superclassNameBase); SubstGenericParametersFromMetadata substitutions(self); - MetadataResponse response = - swift_getTypeByMangledName(request, superclassName, - substitutions.getGenericArgs(), + auto result = swift_getTypeByMangledName( + request, superclassName, substitutions.getGenericArgs(), [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getResponse(); - auto superclass = response.Value; - if (!superclass) { - fatalError(0, - "failed to demangle superclass of %s from mangled name '%s'\n", - self->getDescription()->Name.get(), - superclassName.str().c_str()); + }); + if (auto *error = result.getError()) { + fatalError( + 0, "failed to demangle superclass of %s from mangled name '%s': %s\n", + self->getDescription()->Name.get(), superclassName.str().c_str(), + error->copyErrorString()); } - return response; + return result.getType().getResponse(); } else { return MetadataResponse(); } @@ -4928,12 +4926,12 @@ swift_getAssociatedTypeWitnessSlowImpl( Demangle::makeSymbolicMangledNameStringRef(mangledNameBase); // Demangle the associated type. - MetadataResponse response; + TypeLookupErrorOr result = TypeInfo(); if (inProtocolContext) { // The protocol's Self is the only generic parameter that can occur in the // type. - response = - swift_getTypeByMangledName(request, mangledName, nullptr, + result = swift_getTypeByMangledName( + request, mangledName, nullptr, [conformingType](unsigned depth, unsigned index) -> const Metadata * { if (depth == 0 && index == 0) return conformingType; @@ -4950,7 +4948,7 @@ swift_getAssociatedTypeWitnessSlowImpl( return swift_getAssociatedConformanceWitness(wtable, conformingType, type, reqBase, dependentDescriptor); - }).getResponse(); + }); } else { // The generic parameters in the associated type name are those of the // conforming type. @@ -4960,29 +4958,30 @@ swift_getAssociatedTypeWitnessSlowImpl( auto originalConformingType = findConformingSuperclass(conformingType, conformance); SubstGenericParametersFromMetadata substitutions(originalConformingType); - response = swift_getTypeByMangledName(request, mangledName, - substitutions.getGenericArgs(), - [&substitutions](unsigned depth, unsigned index) { - return substitutions.getMetadata(depth, index); - }, - [&substitutions](const Metadata *type, unsigned index) { - return substitutions.getWitnessTable(type, index); - }).getResponse(); + result = swift_getTypeByMangledName( + request, mangledName, substitutions.getGenericArgs(), + [&substitutions](unsigned depth, unsigned index) { + return substitutions.getMetadata(depth, index); + }, + [&substitutions](const Metadata *type, unsigned index) { + return substitutions.getWitnessTable(type, index); + }); } + auto *error = result.getError(); + MetadataResponse response = result.getType().getResponse(); auto assocTypeMetadata = response.Value; - - if (!assocTypeMetadata) { + if (error || !assocTypeMetadata) { + const char *errStr = error ? error->copyErrorString() + : "NULL metadata but no error was provided"; auto conformingTypeNameInfo = swift_getTypeName(conformingType, true); StringRef conformingTypeName(conformingTypeNameInfo.data, conformingTypeNameInfo.length); StringRef assocTypeName = findAssociatedTypeName(protocol, assocType); fatalError(0, "failed to demangle witness for associated type '%s' in " - "conformance '%s: %s' from mangled name '%s'\n", - assocTypeName.str().c_str(), - conformingTypeName.str().c_str(), - protocol->Name.get(), - mangledName.str().c_str()); + "conformance '%s: %s' from mangled name '%s' - %s\n", + assocTypeName.str().c_str(), conformingTypeName.str().c_str(), + protocol->Name.get(), mangledName.str().c_str(), errStr); } assert((uintptr_t(assocTypeMetadata) & @@ -5935,7 +5934,7 @@ void swift::verifyMangledNameRoundtrip(const Metadata *metadata) { nullptr, [](unsigned, unsigned){ return nullptr; }, [](const Metadata *, unsigned) { return nullptr; }) - .getMetadata(); + .getType().getMetadata(); if (metadata != result) swift::warning(RuntimeErrorFlagNone, "Metadata mangled name failed to roundtrip: %p -> %s -> %p\n", diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 93ed4227928eb..c0c2f7c0c4c9d 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -961,13 +961,54 @@ getLocalGenericParams(const ContextDescriptor *context) { return genericContext->getGenericParams().slice(startParamIndex); } -static bool +static llvm::Optional _gatherGenericParameters(const ContextDescriptor *context, llvm::ArrayRef genericArgs, const Metadata *parent, llvm::SmallVectorImpl &genericParamCounts, llvm::SmallVectorImpl &allGenericArgsVec, Demangler &demangler) { + auto makeCommonErrorStringGetter = [&] { + auto metadataVector = genericArgs.vec(); + return [=] { + std::string str; + + str += "_gatherGenericParameters: context: "; + + SymbolInfo contextInfo; + if (lookupSymbol(context, &contextInfo)) { + str += contextInfo.symbolName.get(); + str += " "; + } + + char *contextStr; + swift_asprintf(&contextStr, "%p", context); + str += contextStr; + free(contextStr); + + str += " <"; + + bool first = true; + for (const Metadata *metadata : genericArgs) { + if (!first) + str += ", "; + first = false; + str += nameForMetadata(metadata); + } + + str += "> "; + + str += "parent: "; + if (parent) + str += nameForMetadata(parent); + else + str += ""; + str += " - "; + + return str; + }; + }; + // Figure out the various levels of generic parameters we have in // this type. (void)_gatherGenericParameterCounts(context, @@ -981,7 +1022,15 @@ _gatherGenericParameters(const ContextDescriptor *context, } else if (genericArgs.size() == numTotalGenericParams && !parent) { // Okay: genericArgs is the complete set of generic arguments. } else { - return false; + auto commonString = makeCommonErrorStringGetter(); + auto genericArgsSize = genericArgs.size(); + return TypeLookupError([=] { + return commonString() + "incorrect number of generic args (" + + std::to_string(genericArgsSize) + "), " + + std::to_string(getLocalGenericParams(context).size()) + + " local params, " + std::to_string(numTotalGenericParams) + + " total params"; + }); } // If there are generic parameters at any level, check the generic @@ -1008,15 +1057,30 @@ _gatherGenericParameters(const ContextDescriptor *context, auto genericParams = generics->getGenericParams(); unsigned n = genericParams.size(); if (allGenericArgs.size() != n) { - return false; + auto commonString = makeCommonErrorStringGetter(); + auto argsVecSize = allGenericArgsVec.size(); + return TypeLookupError([=] { + return commonString() + "have " + std::to_string(argsVecSize) + + "generic args, expected " + std::to_string(n); + }); } for (unsigned i = 0; i != n; ++i) { const auto ¶m = genericParams[i]; - if (param.getKind() != GenericParamKind::Type) - return false; - if (param.hasExtraArgument()) - return false; - + if (param.getKind() != GenericParamKind::Type) { + auto commonString = makeCommonErrorStringGetter(); + return TypeLookupError([=] { + return commonString() + "param " + std::to_string(i) + + " has unexpected kind " + + std::to_string(static_cast(param.getKind())); + }); + } + if (param.hasExtraArgument()) { + auto commonString = makeCommonErrorStringGetter(); + return TypeLookupError([=] { + return commonString() + "param " + std::to_string(i) + + "has extra argument"; + }); + } if (param.hasKeyArgument()) allGenericArgsVec.push_back(allGenericArgs[i]); } @@ -1028,26 +1092,33 @@ _gatherGenericParameters(const ContextDescriptor *context, // any extra arguments we need for the instantiation function. SubstGenericParametersFromWrittenArgs substitutions(allGenericArgs, genericParamCounts); - bool failed = - _checkGenericRequirements(generics->getGenericRequirements(), - allGenericArgsVec, + auto error = _checkGenericRequirements( + generics->getGenericRequirements(), allGenericArgsVec, [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); }); - if (failed) - return false; + if (error) + return *error; // If we still have the wrong number of generic arguments, this is // some kind of metadata mismatch. if (generics->getGenericContextHeader().getNumArguments() != - allGenericArgsVec.size()) - return false; + allGenericArgsVec.size()) { + auto commonString = makeCommonErrorStringGetter(); + auto argsVecSize = allGenericArgsVec.size(); + return TypeLookupError([=] { + return commonString() + "generic argument count mismatch, expected " + + std::to_string( + generics->getGenericContextHeader().getNumArguments()) + + ", have " + std::to_string(argsVecSize); + }); + } } - return true; + return llvm::None; } namespace { @@ -1175,7 +1246,7 @@ class DecodedMetadataBuilder { Demangle::NodeFactory &getNodeFactory() { return demangler; } - BuiltType + TypeLookupErrorOr resolveOpaqueType(NodePointer opaqueDecl, llvm::ArrayRef> genericArgs, unsigned ordinal) { @@ -1193,12 +1264,10 @@ class DecodedMetadataBuilder { llvm::SmallVector genericParamCounts; llvm::SmallVector allGenericArgsVec; - if (!_gatherGenericParameters(outerContext, - allGenericArgs, - BuiltType(), /* no parent */ - genericParamCounts, allGenericArgsVec, - demangler)) - return BuiltType(); + if (auto error = _gatherGenericParameters( + outerContext, allGenericArgs, BuiltType(), /* no parent */ + genericParamCounts, allGenericArgsVec, demangler)) + return *error; auto mangledName = descriptor->getUnderlyingTypeArgument(ordinal); SubstGenericParametersFromMetadata substitutions(descriptor, @@ -1210,7 +1279,7 @@ class DecodedMetadataBuilder { }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } BuiltTypeDecl createTypeDecl(NodePointer node, @@ -1245,8 +1314,9 @@ class DecodedMetadataBuilder { return ProtocolDescriptorRef(); #endif } - - BuiltType createObjCClassType(const std::string &mangledName) const { + + TypeLookupErrorOr + createObjCClassType(const std::string &mangledName) const { #if SWIFT_OBJC_INTEROP auto objcClass = objc_getClass(mangledName.c_str()); return swift_getObjCClassMetadata((const ClassMetadata *)objcClass); @@ -1255,7 +1325,7 @@ class DecodedMetadataBuilder { #endif } - BuiltType + TypeLookupErrorOr createBoundGenericObjCClassType(const std::string &mangledName, llvm::ArrayRef args) const { // Generic arguments of lightweight Objective-C generic classes are not @@ -1263,24 +1333,25 @@ class DecodedMetadataBuilder { return createObjCClassType(mangledName); } - BuiltType createNominalType(BuiltTypeDecl metadataOrTypeDecl, - BuiltType parent) const { + TypeLookupErrorOr + createNominalType(BuiltTypeDecl metadataOrTypeDecl, BuiltType parent) const { // Treat nominal type creation the same way as generic type creation, // but with no generic arguments at this level. return createBoundGenericType(metadataOrTypeDecl, { }, parent); } - BuiltType createTypeAliasType(BuiltTypeDecl typeAliasDecl, - BuiltType parent) const { + TypeLookupErrorOr createTypeAliasType(BuiltTypeDecl typeAliasDecl, + BuiltType parent) const { // We can't support sugared types here since we have no way to // resolve the underlying type of the type alias. However, some // CF types are mangled as type aliases. return createNominalType(typeAliasDecl, parent); } - BuiltType createBoundGenericType(BuiltTypeDecl anyTypeDecl, - llvm::ArrayRef genericArgs, - BuiltType parent) const { + TypeLookupErrorOr + createBoundGenericType(BuiltTypeDecl anyTypeDecl, + llvm::ArrayRef genericArgs, + BuiltType parent) const { auto typeDecl = dyn_cast(anyTypeDecl); if (!typeDecl) { if (auto protocol = dyn_cast(anyTypeDecl)) @@ -1294,13 +1365,11 @@ class DecodedMetadataBuilder { llvm::SmallVector genericParamCounts; llvm::SmallVector allGenericArgsVec; - if (!_gatherGenericParameters(typeDecl, - genericArgs, - parent, - genericParamCounts, allGenericArgsVec, - demangler)) - return BuiltType(); - + if (auto error = _gatherGenericParameters(typeDecl, genericArgs, parent, + genericParamCounts, + allGenericArgsVec, demangler)) + return *error; + // Call the access function. auto accessFunction = typeDecl->getAccessFunction(); if (!accessFunction) return BuiltType(); @@ -1308,8 +1377,8 @@ class DecodedMetadataBuilder { return accessFunction(MetadataState::Abstract, allGenericArgsVec).Value; } - BuiltType createBuiltinType(StringRef builtinName, - StringRef mangledName) const { + TypeLookupErrorOr createBuiltinType(StringRef builtinName, + StringRef mangledName) const { #define BUILTIN_TYPE(Symbol, _) \ if (mangledName.equals(#Symbol)) \ return &METADATA_SYM(Symbol).base; @@ -1317,19 +1386,19 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType createMetatypeType( + TypeLookupErrorOr createMetatypeType( BuiltType instance, llvm::Optional repr = None) const { return swift_getMetatypeMetadata(instance); } - BuiltType createExistentialMetatypeType( + TypeLookupErrorOr createExistentialMetatypeType( BuiltType instance, llvm::Optional repr = None) const { return swift_getExistentialMetatypeMetadata(instance); } - BuiltType + TypeLookupErrorOr createProtocolCompositionType(llvm::ArrayRef protocols, BuiltType superclass, bool isClassBound) const { // Determine whether we have a class bound. @@ -1349,13 +1418,13 @@ class DecodedMetadataBuilder { protocols.size(), protocols.data()); } - BuiltType createDynamicSelfType(BuiltType selfType) const { + TypeLookupErrorOr createDynamicSelfType(BuiltType selfType) const { // Free-standing mangled type strings should not contain DynamicSelfType. return BuiltType(); } - BuiltType createGenericTypeParameterType(unsigned depth, - unsigned index) const { + TypeLookupErrorOr + createGenericTypeParameterType(unsigned depth, unsigned index) const { // Use the callback, when provided. if (substGenericParameter) return substGenericParameter(depth, index); @@ -1363,7 +1432,7 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType + TypeLookupErrorOr createFunctionType(llvm::ArrayRef> params, BuiltType result, FunctionTypeFlags flags) const { llvm::SmallVector paramTypes; @@ -1386,7 +1455,7 @@ class DecodedMetadataBuilder { result); } - BuiltType createImplFunctionType( + TypeLookupErrorOr createImplFunctionType( Demangle::ImplParameterConvention calleeConvention, llvm::ArrayRef> params, llvm::ArrayRef> results, @@ -1396,8 +1465,9 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType createTupleType(llvm::ArrayRef elements, - std::string labels) const { + TypeLookupErrorOr + createTupleType(llvm::ArrayRef elements, + std::string labels) const { auto flags = TupleTypeFlags().withNumElements(elements.size()); if (!labels.empty()) flags = flags.withNonConstantLabels(true); @@ -1408,13 +1478,15 @@ class DecodedMetadataBuilder { .Value; } - BuiltType createDependentMemberType(StringRef name, BuiltType base) const { + TypeLookupErrorOr createDependentMemberType(StringRef name, + BuiltType base) const { // Should not have unresolved dependent member types here. return BuiltType(); } - BuiltType createDependentMemberType(StringRef name, BuiltType base, - BuiltProtocolDecl protocol) const { + TypeLookupErrorOr + createDependentMemberType(StringRef name, BuiltType base, + BuiltProtocolDecl protocol) const { #if SWIFT_OBJC_INTEROP if (protocol.isObjC()) return BuiltType(); @@ -1438,14 +1510,14 @@ class DecodedMetadataBuilder { *assocType).Value; } -#define REF_STORAGE(Name, ...) \ - BuiltType create##Name##StorageType(BuiltType base) { \ - ReferenceOwnership.set##Name(); \ - return base; \ +#define REF_STORAGE(Name, ...) \ + TypeLookupErrorOr create##Name##StorageType(BuiltType base) { \ + ReferenceOwnership.set##Name(); \ + return base; \ } #include "swift/AST/ReferenceStorage.def" - BuiltType createSILBoxType(BuiltType base) const { + TypeLookupErrorOr createSILBoxType(BuiltType base) const { // FIXME: Implement. return BuiltType(); } @@ -1454,22 +1526,23 @@ class DecodedMetadataBuilder { return ReferenceOwnership; } - BuiltType createOptionalType(BuiltType base) { + TypeLookupErrorOr createOptionalType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createArrayType(BuiltType base) { + TypeLookupErrorOr createArrayType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createDictionaryType(BuiltType key, BuiltType value) { + TypeLookupErrorOr createDictionaryType(BuiltType key, + BuiltType value) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createParenType(BuiltType base) { + TypeLookupErrorOr createParenType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } @@ -1478,13 +1551,12 @@ class DecodedMetadataBuilder { } SWIFT_CC(swift) -static TypeInfo swift_getTypeByMangledNodeImpl( - MetadataRequest request, - Demangler &demangler, - Demangle::NodePointer node, - const void * const *origArgumentVector, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +static TypeLookupErrorOr +swift_getTypeByMangledNodeImpl(MetadataRequest request, Demangler &demangler, + Demangle::NodePointer node, + const void *const *origArgumentVector, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { // Simply call an accessor function if that's all we got. if (node->getKind() == Node::Kind::AccessorFunctionReference) { // The accessor function is passed the pointer to the original argument @@ -1504,22 +1576,23 @@ static TypeInfo swift_getTypeByMangledNodeImpl( DecodedMetadataBuilder builder(demangler, substGenericParam, substWitnessTable); auto type = Demangle::decodeMangledType(builder, node); - if (!type) { - return {MetadataResponse{nullptr, MetadataState::Complete}, - TypeReferenceOwnership()}; + if (type.isError()) { + return *type.getError(); + } + if (!type.getType()) { + return TypeLookupError("NULL type but no error provided"); } - return {swift_checkMetadataState(request, type), - builder.getReferenceOwnership()}; + return TypeInfo{swift_checkMetadataState(request, type.getType()), + builder.getReferenceOwnership()}; } SWIFT_CC(swift) -static TypeInfo swift_getTypeByMangledNameImpl( - MetadataRequest request, - StringRef typeName, - const void * const *origArgumentVector, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +static TypeLookupErrorOr +swift_getTypeByMangledNameImpl(MetadataRequest request, StringRef typeName, + const void *const *origArgumentVector, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { DemanglerForRuntimeTypeResolution> demangler; NodePointer node; @@ -1587,7 +1660,7 @@ swift_getTypeByMangledNameInEnvironment( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1607,7 +1680,7 @@ swift_getTypeByMangledNameInEnvironmentInMetadataState( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1626,7 +1699,7 @@ swift_getTypeByMangledNameInContext( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1646,7 +1719,7 @@ swift_getTypeByMangledNameInContextInMetadataState( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } /// Demangle a mangled name, but don't allow symbolic references. @@ -1661,7 +1734,7 @@ swift_stdlib_getTypeByMangledNameUntrusted(const char *typeNameStart, } return swift_getTypeByMangledName(MetadataState::Complete, typeName, nullptr, - {}, {}).getMetadata(); + {}, {}).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1680,7 +1753,7 @@ swift_getOpaqueTypeMetadata(MetadataRequest request, }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getResponse(); + }).getType().getResponse(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1735,7 +1808,7 @@ getObjCClassByMangledName(const char * _Nonnull typeName, }, [&](const Metadata *type, unsigned index) { return nullptr; - }).getMetadata(); + }).getType().getMetadata(); } else { metadata = swift_stdlib_getTypeByMangledNameUntrusted(typeStr.data(), typeStr.size()); @@ -2068,7 +2141,7 @@ void swift::gatherWrittenGenericArgs( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); continue; } diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index c46e8ff9a9b38..2f5e7232cc55d 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -17,7 +17,10 @@ #ifndef SWIFT_RUNTIME_PRIVATE_H #define SWIFT_RUNTIME_PRIVATE_H +#include + #include "swift/Demangling/Demangler.h" +#include "swift/Demangling/TypeLookupError.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Metadata.h" @@ -77,6 +80,8 @@ class TypeInfo { const Metadata *getMetadata() const { return Response.Value; } MetadataResponse getResponse() const { return Response; } + operator bool() const { return getMetadata(); } + #define REF_STORAGE(Name, ...) \ bool is##Name() const { return ReferenceOwnership.is##Name(); } #include "swift/AST/ReferenceStorage.def" @@ -369,7 +374,7 @@ class TypeInfo { /// \p substWitnessTable Function that provides witness tables given a /// particular dependent conformance index. SWIFT_CC(swift) - TypeInfo swift_getTypeByMangledNode( + TypeLookupErrorOr swift_getTypeByMangledNode( MetadataRequest request, Demangler &demangler, Demangle::NodePointer node, @@ -384,7 +389,7 @@ class TypeInfo { /// \p substWitnessTable Function that provides witness tables given a /// particular dependent conformance index. SWIFT_CC(swift) - TypeInfo swift_getTypeByMangledName( + TypeLookupErrorOr swift_getTypeByMangledName( MetadataRequest request, StringRef typeName, const void * const *arguments, @@ -447,12 +452,12 @@ class TypeInfo { /// generic requirements (e.g., those that need to be /// passed to an instantiation function) will be added to this vector. /// - /// \returns true if an error occurred, false otherwise. - bool _checkGenericRequirements( - llvm::ArrayRef requirements, - llvm::SmallVectorImpl &extraArguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable); + /// \returns the error if an error occurred, None otherwise. + llvm::Optional _checkGenericRequirements( + llvm::ArrayRef requirements, + llvm::SmallVectorImpl &extraArguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable); /// A helper function which avoids performing a store if the destination /// address already contains the source value. This is useful when diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index e373d2a50848e..c434011faea85 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -165,15 +165,16 @@ ProtocolConformanceDescriptor::getWitnessTable(const Metadata *type) const { llvm::SmallVector conditionalArgs; if (hasConditionalRequirements()) { SubstGenericParametersFromMetadata substitutions(type); - bool failed = - _checkGenericRequirements(getConditionalRequirements(), conditionalArgs, + auto error = _checkGenericRequirements( + getConditionalRequirements(), conditionalArgs, [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); }); - if (failed) return nullptr; + if (error) + return nullptr; } return swift_getWitnessTable(this, type, conditionalArgs.data()); @@ -642,31 +643,36 @@ static bool isSubclass(const Metadata *subclass, const Metadata *superclass) { }); } -bool swift::_checkGenericRequirements( - llvm::ArrayRef requirements, - llvm::SmallVectorImpl &extraArguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +llvm::Optional swift::_checkGenericRequirements( + llvm::ArrayRef requirements, + llvm::SmallVectorImpl &extraArguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { for (const auto &req : requirements) { // Make sure we understand the requirement we're dealing with. - if (!req.hasKnownKind()) return true; + if (!req.hasKnownKind()) + return TypeLookupError("unknown kind"); // Resolve the subject generic parameter. - const Metadata *subjectType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getParam(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!subjectType) - return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getParam(), extraArguments.data(), + substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + const Metadata *subjectType = result.getType().getMetadata(); // Check the requirement. switch (req.getKind()) { case GenericRequirementKind::Protocol: { const WitnessTable *witnessTable = nullptr; if (!_conformsToProtocol(nullptr, subjectType, req.getProtocol(), - &witnessTable)) - return true; + &witnessTable)) { + const char *protoName = + req.getProtocol() ? req.getProtocol().getName() : ""; + return TypeLookupError( + "subject type %s does not conform to protocol %s", req.getParam(), + protoName); + } // If we need a witness table, add it. if (req.getProtocol().needsWitnessTable()) { @@ -679,17 +685,19 @@ bool swift::_checkGenericRequirements( case GenericRequirementKind::SameType: { // Demangle the second type under the given substitutions. - auto otherType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getMangledTypeName(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!otherType) return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getMangledTypeName(), + extraArguments.data(), substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + auto otherType = result.getType().getMetadata(); assert(!req.getFlags().hasExtraArgument()); // Check that the types are equivalent. - if (subjectType != otherType) return true; + if (subjectType != otherType) + return TypeLookupError("subject type %s does not match %s", + req.getParam(), req.getMangledTypeName()); continue; } @@ -698,22 +706,24 @@ bool swift::_checkGenericRequirements( switch (req.getLayout()) { case GenericRequirementLayoutKind::Class: if (!subjectType->satisfiesClassConstraint()) - return true; + return TypeLookupError( + "subject type %s does not satisfy class constraint", + req.getParam()); continue; } // Unknown layout. - return true; + return TypeLookupError("unknown layout kind %u", req.getLayout()); } case GenericRequirementKind::BaseClass: { // Demangle the base type under the given substitutions. - auto baseType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getMangledTypeName(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!baseType) return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getMangledTypeName(), + extraArguments.data(), substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + auto baseType = result.getType().getMetadata(); // If the type which is constrained to a base class is an existential // type, and if that existential type includes a superclass constraint, @@ -725,7 +735,8 @@ bool swift::_checkGenericRequirements( } if (!isSubclass(subjectType, baseType)) - return true; + return TypeLookupError("%s is not subclass of %s", req.getParam(), + req.getMangledTypeName()); continue; } @@ -737,11 +748,12 @@ bool swift::_checkGenericRequirements( } // Unknown generic requirement kind. - return true; + return TypeLookupError("unknown generic requirement kind %u", + req.getKind()); } // Success! - return false; + return llvm::None; } const Metadata *swift::findConformingSuperclass( diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm index 821fecfb7fb0b..0206237d2b44b 100644 --- a/stdlib/public/runtime/ReflectionMirror.mm +++ b/stdlib/public/runtime/ReflectionMirror.mm @@ -400,27 +400,33 @@ static bool _shouldReportMissingReflectionMetadataWarnings() { auto typeName = field.getMangledTypeName(); SubstGenericParametersFromMetadata substitutions(base); - auto typeInfo = swift_getTypeByMangledName(MetadataState::Complete, - typeName, - substitutions.getGenericArgs(), - [&substitutions](unsigned depth, unsigned index) { - return substitutions.getMetadata(depth, index); - }, - [&substitutions](const Metadata *type, unsigned index) { - return substitutions.getWitnessTable(type, index); - }); + auto result = swift_getTypeByMangledName( + MetadataState::Complete, typeName, substitutions.getGenericArgs(), + [&substitutions](unsigned depth, unsigned index) { + return substitutions.getMetadata(depth, index); + }, + [&substitutions](const Metadata *type, unsigned index) { + return substitutions.getWitnessTable(type, index); + }); // If demangling the type failed, pretend it's an empty type instead with // a log message. - if (!typeInfo.getMetadata()) { + TypeInfo typeInfo; + if (result.isError()) { typeInfo = TypeInfo({&METADATA_SYM(EMPTY_TUPLE_MANGLING), MetadataState::Complete}, {}); + + auto *error = result.getError(); + char *str = error->copyErrorString(); missing_reflection_metadata_warning( - "warning: the Swift runtime was unable to demangle the type " - "of field '%*s'. the mangled type name is '%*s'. this field will " - "show up as an empty tuple in Mirrors\n", - (int)name.size(), name.data(), - (int)typeName.size(), typeName.data()); + "warning: the Swift runtime was unable to demangle the type " + "of field '%*s'. the mangled type name is '%*s': %s. this field will " + "show up as an empty tuple in Mirrors\n", + (int)name.size(), name.data(), (int)typeName.size(), typeName.data(), + str); + error->freeErrorString(str); + } else { + typeInfo = result.getType(); } auto fieldType = FieldType(typeInfo.getMetadata()); diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index f377a77d6f106..ba33dd19abd69 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -26,11 +26,13 @@ #include "llvm/ADT/StringRef.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/Casting.h" +#include "swift/Runtime/Debug.h" #include "swift/Runtime/EnvironmentVariables.h" #include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" #include "swift/Runtime/ObjCBridge.h" +#include "swift/Runtime/Portability.h" #include "swift/Strings.h" #include "../SwiftShims/RuntimeShims.h" #include "../SwiftShims/AssertionReporting.h" @@ -39,7 +41,6 @@ #include "Private.h" #include "SwiftObject.h" #include "WeakReference.h" -#include "swift/Runtime/Debug.h" #if SWIFT_OBJC_INTEROP #include #endif diff --git a/stdlib/public/stubs/Assert.cpp b/stdlib/public/stubs/Assert.cpp index 62135b2312b1c..fa0169a5ad6b8 100644 --- a/stdlib/public/stubs/Assert.cpp +++ b/stdlib/public/stubs/Assert.cpp @@ -12,6 +12,7 @@ #include "swift/Runtime/Config.h" #include "swift/Runtime/Debug.h" +#include "swift/Runtime/Portability.h" #include "../SwiftShims/AssertionReporting.h" #include #include diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp index c06ec35de5f81..8846f4452e855 100644 --- a/tools/swift-reflection-dump/swift-reflection-dump.cpp +++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp @@ -668,12 +668,15 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, Demangle::Demangler Dem; auto Demangled = Dem.demangleType(Line); - auto *TypeRef = - swift::Demangle::decodeMangledType(builder, Demangled); - if (TypeRef == nullptr) { - fprintf(file, "Invalid typeref:%s\n", Line.c_str()); + auto Result = swift::Demangle::decodeMangledType(builder, Demangled); + if (Result.isError()) { + auto *error = Result.getError(); + char *str = error->copyErrorString(); + fprintf(file, "Invalid typeref:%s - %s\n", Line.c_str(), str); + error->freeErrorString(str); continue; } + auto TypeRef = Result.getType(); TypeRef->dump(file); auto *TypeInfo = builder.getTypeConverter().getTypeInfo(TypeRef); diff --git a/unittests/runtime/CompatibilityOverride.cpp b/unittests/runtime/CompatibilityOverride.cpp index 80a9b086980b9..6056f26117930 100644 --- a/unittests/runtime/CompatibilityOverride.cpp +++ b/unittests/runtime/CompatibilityOverride.cpp @@ -35,8 +35,8 @@ namespace { return MetadataResponse{nullptr, MetadataState::Complete}; } - template<> - TypeInfo getEmptyValue() { + template <> + TypeLookupErrorOr getEmptyValue>() { return TypeInfo(); } } @@ -172,13 +172,13 @@ TEST_F(CompatibilityOverrideTest, test_swift_getTypeByMangledNode) { Demangler demangler; auto Result = swift_getTypeByMangledNode(MetadataState::Abstract, demangler, nullptr, nullptr, nullptr,nullptr); - ASSERT_EQ(Result.getMetadata(), nullptr); + ASSERT_EQ(Result.getType().getMetadata(), nullptr); } TEST_F(CompatibilityOverrideTest, test_swift_getTypeByMangledName) { auto Result = swift_getTypeByMangledName(MetadataState::Abstract, "", nullptr, nullptr, nullptr); - ASSERT_EQ(Result.getMetadata(), nullptr); + ASSERT_EQ(Result.getType().getMetadata(), nullptr); } TEST_F(CompatibilityOverrideTest, test_swift_getAssociatedTypeWitnessSlow) { From 539b241bf2b36b7d7e9362c30d7a39d1978bad38 Mon Sep 17 00:00:00 2001 From: tbkka Date: Fri, 28 Aug 2020 13:26:29 -0700 Subject: [PATCH 423/663] Fallback to building Cmake from source on all platforms, not just Linux (#33543) * Fallback to building Cmake from source on all platforms, not just Linux * Remove no-longer-used import --- utils/swift_build_support/swift_build_support/cmake.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/utils/swift_build_support/swift_build_support/cmake.py b/utils/swift_build_support/swift_build_support/cmake.py index 85a97dfa747e2..5ef74e0cf5ee4 100644 --- a/utils/swift_build_support/swift_build_support/cmake.py +++ b/utils/swift_build_support/swift_build_support/cmake.py @@ -18,7 +18,6 @@ from __future__ import absolute_import, unicode_literals import os -import platform import re from numbers import Number @@ -256,9 +255,6 @@ def build_cmake(self, source_root, build_root): # the source and build the source if necessary. Returns the path to the # cmake binary. def check_cmake_version(self, source_root, build_root): - if platform.system() != 'Linux': - return - cmake_source_dir = os.path.join(source_root, 'cmake') # If the source is not checked out then don't attempt to build cmake. if not os.path.isdir(cmake_source_dir): From 6ad2757bef212510785eef8a9755d09140b54978 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 28 Aug 2020 13:58:02 -0700 Subject: [PATCH 424/663] [Concurrency] Use completion/completionHandler parameter names for async import Extend the check for completion handler parameters to also consider the name of the parameter (not its argument label). If it's `completion` or `completionHandler`, we have a completion handler. This extends our API coverage for importing Objective-C methods with completion handlers as 'async'. --- lib/ClangImporter/ImportName.cpp | 33 ++++++++++++------- test/ClangImporter/objc_async.swift | 2 ++ test/IDE/print_clang_objc_async.swift | 1 + .../usr/include/ObjCConcurrency.h | 2 ++ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 791c695ff1b91..fc0313bbc91df 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1213,10 +1213,13 @@ NameImporter::considerAsyncImport( // handler. Optional newBaseName; if (isCompletionHandlerParamName(paramNames[completionHandlerParamNameIndex])) { - // The parameter itself has an appropriate name. + // The argument label itself has an appropriate name. } else if (!hasCustomName && completionHandlerParamIndex == 0 && (newBaseName = isCompletionHandlerInBaseName(baseName))) { // The base name implies that the first parameter is a completion handler. + } else if (isCompletionHandlerParamName( + params[completionHandlerParamIndex]->getName())) { + // The parameter has an appropriate name. } else { return None; } @@ -1238,6 +1241,10 @@ NameImporter::considerAsyncImport( if (isInitializer) return notAsync("initializers cannot be async"); + // Accessors are never imported as async. + if (clangDecl->isPropertyAccessor()) + return notAsync("method is a property accessor"); + // Check whether we method has a suitable return type. if (clangDecl->getReturnType()->isVoidType()) { // 'void' is the common case; the method produces no synchronous result. @@ -1515,7 +1522,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, else if (parsedName.IsSetter) result.info.accessorKind = ImportedAccessorKind::PropertySetter; - if (method && parsedName.IsFunctionName) { + if (method && parsedName.IsFunctionName && + result.info.accessorKind == ImportedAccessorKind::None) { // Get the parameters. ArrayRef params{method->param_begin(), method->param_end()}; @@ -1787,16 +1795,6 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.errorInfo = *errorInfo; } - if (version.supportsConcurrency()) { - if (auto asyncInfo = considerAsyncImport( - objcMethod, baseName, argumentNames, params, isInitializer, - /*hasCustomName=*/false, - result.getErrorInfo())) { - result.info.hasAsyncInfo = true; - result.info.asyncInfo = *asyncInfo; - } - } - isFunction = true; // Is this one of the accessors for subscripts? @@ -1814,6 +1812,17 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.accessorKind = ImportedAccessorKind::SubscriptSetter; } + if (version.supportsConcurrency() && + result.info.accessorKind == ImportedAccessorKind::None) { + if (auto asyncInfo = considerAsyncImport( + objcMethod, baseName, argumentNames, params, isInitializer, + /*hasCustomName=*/false, + result.getErrorInfo())) { + result.info.hasAsyncInfo = true; + result.info.asyncInfo = *asyncInfo; + } + } + break; } } diff --git a/test/ClangImporter/objc_async.swift b/test/ClangImporter/objc_async.swift index 8ec33ae643905..15b149a89c5dd 100644 --- a/test/ClangImporter/objc_async.swift +++ b/test/ClangImporter/objc_async.swift @@ -11,6 +11,8 @@ func testSlowServer(slowServer: SlowServer) async { let _: String = await slowServer.findAnswerFailingly() ?? "nope" // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} + let _: Void = await slowServer.doSomethingFun("jump") + let _: (Int) -> Void = slowServer.completionHandler } func testSlowServerOldSchool(slowServer: SlowServer) { diff --git a/test/IDE/print_clang_objc_async.swift b/test/IDE/print_clang_objc_async.swift index 6e4539de8825c..7d3029fff8be6 100644 --- a/test/IDE/print_clang_objc_async.swift +++ b/test/IDE/print_clang_objc_async.swift @@ -16,4 +16,5 @@ // CHECK-DAG: func findAnswer() async throws -> String? // CHECK-DAG: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws // CHECK-DAG: func findAnswerFailingly() async throws -> String? +// CHECK-DAG: func doSomethingFun(_ operation: String) async // CHECK: {{^[}]$}} diff --git a/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h index 9903bd0a91a64..b03e3530a4968 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h +++ b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h @@ -9,6 +9,8 @@ -(void)checkAvailabilityWithCompletionHandler:(void (^)(BOOL isAvailable))completionHandler; -(void)findAnswerAsynchronously:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswer(completionHandler:)"))); -(BOOL)findAnswerFailinglyWithError:(NSError * _Nullable * _Nullable)error completion:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswerFailingly(completionHandler:)"))); +-(void)doSomethingFun:(NSString *)operation then:(void (^)(void))completionHandler; +@property(readwrite) void (^completionHandler)(NSInteger); @end #pragma clang assume_nonnull end From 67eca9b79439ca7d30663c93884abbd8a9306cde Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 28 Aug 2020 13:39:55 -0700 Subject: [PATCH 425/663] [DependencyScanner] Change the scanner order to resolve placeholders first. This is meant to address a problem that arises on incremental package builds: A re-scan on an already-built package instead of a placeholder dependency produces a graph that contains a dependency consisting solely of the previously-built swiftmodule. This is not the behaviour we would like. Instead, we should respect that this is a placeholder dependency and ensure that the dependency graph for that dependency itself captures the fact that a previously-built module exists using compiledModuleCandidates field of the dependency graph. --- .../Serialization/ModuleDependencyScanner.h | 27 ++++++++++++++++--- lib/Serialization/ModuleDependencyScanner.cpp | 10 +++++-- .../can_import_placeholder.swift | 10 ------- .../module_deps_external.swift | 10 ------- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/include/swift/Serialization/ModuleDependencyScanner.h b/include/swift/Serialization/ModuleDependencyScanner.h index 07006770d8f49..dd12f8ee98008 100644 --- a/include/swift/Serialization/ModuleDependencyScanner.h +++ b/include/swift/Serialization/ModuleDependencyScanner.h @@ -19,6 +19,16 @@ namespace swift { /// for the purpose of determining dependencies, but does not attempt to /// load the module files. class ModuleDependencyScanner : public SerializedModuleLoaderBase { + public: + enum ScannerKind { + MDS_plain, + MDS_placeholder + }; + + private: + /// The kind of scanner this is (LLVM-style RTTI) + const ScannerKind kind; + /// The module we're scanning dependencies of. Identifier moduleName; @@ -36,10 +46,11 @@ namespace swift { ModuleDependencyScanner( ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, InterfaceSubContextDelegate &astDelegate, - ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift) + ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift, + ScannerKind kind = MDS_plain) : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, /*IgnoreSwiftSourceInfoFile=*/true), - moduleName(moduleName), astDelegate(astDelegate), + kind(kind), moduleName(moduleName), astDelegate(astDelegate), dependencyKind(dependencyKind) {} std::error_code findModuleFilesInDirectory( @@ -55,6 +66,11 @@ namespace swift { SmallVectorImpl &names) const override { llvm_unreachable("Not used"); } + + ScannerKind getKind() const { return kind; } + static bool classof(const ModuleDependencyScanner *MDS) { + return MDS->getKind() == MDS_plain; + } }; /// A ModuleLoader that loads placeholder dependency module stubs specified in @@ -90,7 +106,8 @@ namespace swift { StringRef PlaceholderDependencyModuleMap, InterfaceSubContextDelegate &astDelegate) : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, - ModuleDependenciesKind::SwiftPlaceholder) { + ModuleDependenciesKind::SwiftPlaceholder, + MDS_placeholder) { // FIXME: Find a better place for this map to live, to avoid // doing the parsing on every module. @@ -106,5 +123,9 @@ namespace swift { std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, bool IsFramework) override; + + static bool classof(const ModuleDependencyScanner *MDS) { + return MDS->getKind() == MDS_placeholder; + } }; } diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index fbe77f062b9b6..7f0588858152e 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -176,13 +176,19 @@ Optional SerializedModuleLoaderBase::getModuleDependencies( auto moduleId = Ctx.getIdentifier(moduleName); // Instantiate dependency scanning "loaders". SmallVector, 2> scanners; - scanners.push_back(std::make_unique( - Ctx, LoadMode, moduleId, delegate)); + // Placeholder dependencies must be resolved first, to prevent the ModuleDependencyScanner + // from first discovering artifacts of a previous build. Such artifacts are captured + // as compiledModuleCandidates in the dependency graph of the placeholder dependency module + // itself. scanners.push_back(std::make_unique( Ctx, LoadMode, moduleId, Ctx.SearchPathOpts.PlaceholderDependencyModuleMap, delegate)); + scanners.push_back(std::make_unique( + Ctx, LoadMode, moduleId, delegate)); // Check whether there is a module with this name that we can import. + assert(isa(scanners[0].get()) && + "Expected PlaceholderSwiftModuleScanner as the first dependency scanner loader."); for (auto &scanner : scanners) { if (scanner->canImportModule({moduleId, SourceLoc()})) { // Record the dependencies. diff --git a/test/ScanDependencies/can_import_placeholder.swift b/test/ScanDependencies/can_import_placeholder.swift index 8c14c6b2a125e..777f283fdf0ac 100644 --- a/test/ScanDependencies/can_import_placeholder.swift +++ b/test/ScanDependencies/can_import_placeholder.swift @@ -8,16 +8,6 @@ // RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json // RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"," >> %/t/inputs/map.json // RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json -// RUN: echo "}," >> %/t/inputs/map.json -// RUN: echo "{" >> %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json -// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json -// RUN: echo "}," >> %/t/inputs/map.json -// RUN: echo "{" >> %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json -// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 diff --git a/test/ScanDependencies/module_deps_external.swift b/test/ScanDependencies/module_deps_external.swift index f3b2147a487da..4242028b6d114 100644 --- a/test/ScanDependencies/module_deps_external.swift +++ b/test/ScanDependencies/module_deps_external.swift @@ -8,16 +8,6 @@ // RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json // RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"," >> %/t/inputs/map.json // RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json -// RUN: echo "}," >> %/t/inputs/map.json -// RUN: echo "{" >> %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json -// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json -// RUN: echo "}," >> %/t/inputs/map.json -// RUN: echo "{" >> %/t/inputs/map.json -// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json -// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json -// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json // RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 From c4f05052da564c5f47552af02cb6c185af8b5149 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Fri, 14 Aug 2020 14:58:42 -0700 Subject: [PATCH 426/663] [Parse] Don't drop throws containing a code completion expression. --- lib/Parse/ParseStmt.cpp | 7 ++++--- test/IDE/complete_exception.swift | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index e39f0daf1846b..1a95fc1585f46 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -898,9 +898,7 @@ ParserResult Parser::parseStmtThrow(SourceLoc tryLoc) { exprLoc = Tok.getLoc(); ParserResult Result = parseExpr(diag::expected_expr_throw); - - if (Result.hasCodeCompletion()) - return makeParserCodeCompletionResult(); + bool hasCodeCompletion = Result.hasCodeCompletion(); if (Result.isNull()) Result = makeParserErrorResult(new (Context) ErrorExpr(throwLoc)); @@ -916,6 +914,9 @@ ParserResult Parser::parseStmtThrow(SourceLoc tryLoc) { Result = makeParserResult(new (Context) TryExpr(exprLoc, Result.get())); } + if (hasCodeCompletion) + Result.setHasCodeCompletion(); + return makeParserResult(Result, new (Context) ThrowStmt(throwLoc, Result.get())); } diff --git a/test/IDE/complete_exception.swift b/test/IDE/complete_exception.swift index 48d222ced7565..0a52f94e2928d 100644 --- a/test/IDE/complete_exception.swift +++ b/test/IDE/complete_exception.swift @@ -5,11 +5,13 @@ // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH2 | %FileCheck %s -check-prefix=CATCH2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW2 | %FileCheck %s -check-prefix=THROW2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH3 | %FileCheck %s -check-prefix=CATCH3 +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW3 | %FileCheck %s -check-prefix=THROW3 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH1 | %FileCheck %s -check-prefix=CATCH1 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW1 | %FileCheck %s -check-prefix=THROW1 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH2 | %FileCheck %s -check-prefix=CATCH2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW2 | %FileCheck %s -check-prefix=THROW2 +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW3 | %FileCheck %s -check-prefix=THROW3 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH1 > %t.inside_catch1 // RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch1 @@ -126,11 +128,20 @@ func test005() { // CATCH3: End completions } +func testInvalid() { + try throw Error4.#^THROW3^# +// THROW3: Begin completions +// THROW3: Decl[EnumElement]/CurrNominal: E1[#Error4#]{{; name=.+$}} +// THROW3: Decl[EnumElement]/CurrNominal: E2({#Int32#})[#Error4#]{{; name=.+$}} +// THROW3: End completions +} + //===--- Top-level throw/catch do {} catch #^TOP_LEVEL_CATCH1^# {} throw #^TOP_LEVEL_THROW1^# do {} catch Error4.#^TOP_LEVEL_CATCH2^# {} throw Error4.#^TOP_LEVEL_THROW2^# +try throw Error4.#^TOP_LEVEL_THROW3^# //===--- Inside catch body From 00994f114768917a8037920e99352d872f2aa2b1 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Thu, 27 Aug 2020 14:34:56 -0700 Subject: [PATCH 427/663] [Parse] Stop early exiting when parsing catch statements and ObjCSelector expressions that contain code completions. --- lib/Parse/ParseExpr.cpp | 4 +--- lib/Parse/ParseStmt.cpp | 3 --- test/IDE/complete_exception.swift | 8 ++++---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1d3a63a826d11..474cfb2cade44 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -802,8 +802,6 @@ ParserResult Parser::parseExprSelector() { parseExpr(selectorKind == ObjCSelectorExpr::Method ? diag::expr_selector_expected_method_expr : diag::expr_selector_expected_property_expr); - if (subExpr.hasCodeCompletion()) - return makeParserCodeCompletionResult(); // Parse the closing ')'. SourceLoc rParenLoc; @@ -819,7 +817,7 @@ ParserResult Parser::parseExprSelector() { } // If the subexpression was in error, just propagate the error. - if (subExpr.isParseError()) + if (subExpr.isParseError() && !subExpr.hasCodeCompletion()) return makeParserResult( new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc))); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 1a95fc1585f46..c4a64ca54973e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2013,9 +2013,6 @@ ParserResult Parser::parseStmtCatch() { GuardedPattern PatternResult; parseGuardedPattern(*this, PatternResult, status, boundDecls, GuardedPatternContext::Catch, isFirst); - if (status.hasCodeCompletion()) { - return makeParserCodeCompletionResult(); - } caseLabelItems.emplace_back(PatternResult.ThePattern, PatternResult.WhereLoc, PatternResult.Guard); isFirst = false; diff --git a/test/IDE/complete_exception.swift b/test/IDE/complete_exception.swift index 0a52f94e2928d..a5cef6bb5175b 100644 --- a/test/IDE/complete_exception.swift +++ b/test/IDE/complete_exception.swift @@ -72,10 +72,10 @@ func test001() { do {} catch #^CATCH1^# // CATCH1: Begin completions -// CATCH1-DAG: Decl[Enum]/CurrModule: Error4[#Error4#]; name=Error4{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error3[#Error3#]; name=Error3{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error2[#Error2#]; name=Error2{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error1[#Error1#]; name=Error1{{$}} +// CATCH1-DAG: Decl[Enum]/CurrModule/TypeRelation[Convertible]: Error4[#Error4#]; name=Error4{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error3[#Error3#]; name=Error3{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error2[#Error2#]; name=Error2{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error1[#Error1#]; name=Error1{{$}} // CATCH1-DAG: Keyword[let]/None: let{{; name=.+$}} // CATCH1-DAG: Decl[Class]/CurrModule: NoneError1[#NoneError1#]; name=NoneError1{{$}} // CATCH1-DAG: Decl[Class]/OtherModule[Foundation]/IsSystem: NSError[#NSError#]{{; name=.+$}} From 3e0500d73c1f1efbbc166e22228fd589da19695d Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Mon, 24 Aug 2020 11:39:47 -0700 Subject: [PATCH 428/663] [Parse][IDE] Don't drop default argument init exprs containing code completion exprs and type check them for code completion. Fixes up some tests marked as non-ideal to give the ideal result now too. --- lib/IDE/ExprContextAnalysis.cpp | 5 +++++ lib/Parse/ParsePattern.cpp | 4 +++- test/IDE/complete_unresolved_members.swift | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 787606e321891..ad3a32fb7ada2 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -85,6 +85,11 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { typeCheckPatternBinding(PBD, i); } } + } else if (auto *defaultArg = dyn_cast(DC)) { + if (auto *AFD = dyn_cast(defaultArg->getParent())) { + auto *Param = AFD->getParameters()->get(defaultArg->getIndex()); + (void*)Param->getTypeCheckedDefaultExpr(); + } } break; diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index e26a0dd1cd238..c98ea0c6f04da 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -130,8 +130,10 @@ static ParserStatus parseDefaultArgument( defaultArgs->HasDefaultArgument = true; - if (initR.hasCodeCompletion()) + if (initR.hasCodeCompletion()) { + init = initR.get(); return makeParserCodeCompletionStatus(); + } if (initR.isNull()) return makeParserError(); diff --git a/test/IDE/complete_unresolved_members.swift b/test/IDE/complete_unresolved_members.swift index 7a895c550c665..804d9cd5bcba9 100644 --- a/test/IDE/complete_unresolved_members.swift +++ b/test/IDE/complete_unresolved_members.swift @@ -109,9 +109,9 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERICPARAM_21 | %FileCheck %s -check-prefix=GENERICPARAM_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DECL_MEMBER_INIT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_1 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_2 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_3 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_1 | %FileCheck %s -check-prefix=UNRESOLVED_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_2 | %FileCheck %s -check-prefix=UNRESOLVED_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_3 | %FileCheck %s -check-prefix=UNRESOLVED_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEPARAM_IN_CONTEXTTYPE_1 | %FileCheck %s -check-prefix=TYPEPARAM_IN_CONTEXTTYPE_1 From 89803560f9a1d11d438b06392a9938648aa3be62 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Tue, 25 Aug 2020 21:28:38 -0700 Subject: [PATCH 429/663] [Parse] Perform the single expression function body transform for delayed parsing as well We were previously only doing it when parsing up front. --- include/swift/Parse/Parser.h | 3 +- lib/Parse/ParseDecl.cpp | 129 ++++++++++++++++++----------------- lib/Parse/Parser.cpp | 2 +- 3 files changed, 68 insertions(+), 66 deletions(-) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 723fdcd956a22..7f1b3ddba9249 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1133,8 +1133,7 @@ class Parser { ParseDeclOptions Flags, DeclAttributes &Attributes, bool HasFuncKeyword = true); - ParserResult - parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); + BraceStmt *parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); void parseAbstractFunctionBody(AbstractFunctionDecl *AFD); BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD); ParserResult parseDeclProtocol(ParseDeclOptions Flags, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index aa3cf8ce5cad1..ac374bee7e53b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -6442,10 +6442,9 @@ ParserResult Parser::parseDeclFunc(SourceLoc StaticLoc, return DCC.fixupParserResult(FD); } -/// Parse a function body for \p AFD and returns it without setting the body -/// to \p AFD . -ParserResult -Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { +/// Parse a function body for \p AFD, setting the body to \p AFD before +/// returning it. +BraceStmt *Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { assert(Tok.is(tok::l_brace)); // Enter the arguments for the function into a new function-body scope. We @@ -6473,13 +6472,70 @@ Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { CodeCompletion->completeAccessorBeginning(CCE); RBraceLoc = Tok.getLoc(); consumeToken(tok::code_complete); - return makeParserCodeCompletionResult( - BraceStmt::create(Context, LBraceLoc, ASTNode(CCE), RBraceLoc, - /*implicit*/ true)); + auto *BS = BraceStmt::create(Context, LBraceLoc, ASTNode(CCE), RBraceLoc, + /*implicit*/ true); + AFD->setBodyParsed(BS); + return BS; } } - return parseBraceItemList(diag::invalid_diagnostic); + ParserResult Body = parseBraceItemList(diag::invalid_diagnostic); + if (Body.isNull()) + return nullptr; + + BraceStmt *BS = Body.get(); + AFD->setBodyParsed(BS); + + // If the body consists of a single expression, turn it into a return + // statement. + // + // But don't do this transformation during code completion, as the source + // may be incomplete and the type mismatch in return statement will just + // confuse the type checker. + if (BS->getNumElements() != 1 || Body.hasCodeCompletion()) + return BS; + + auto Element = BS->getFirstElement(); + if (auto *stmt = Element.dyn_cast()) { + if (isa(AFD)) { + if (auto *returnStmt = dyn_cast(stmt)) { + if (!returnStmt->hasResult()) { + auto returnExpr = TupleExpr::createEmpty(Context, + SourceLoc(), + SourceLoc(), + /*implicit*/true); + returnStmt->setResult(returnExpr); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(returnExpr); + } + } + } + } else if (auto *E = Element.dyn_cast()) { + if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { + if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { + // This is an assignment. We don't want to implicitly return + // it. + return BS; + } + } + if (isa(AFD)) { + auto RS = new (Context) ReturnStmt(SourceLoc(), E); + BS->setFirstElement(RS); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(E); + } else if (auto *F = dyn_cast(AFD)) { + if (F->isFailable() && isa(E)) { + // If it's a nil literal, just insert return. This is the only + // legal thing to return. + auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); + BS->setFirstElement(RS); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(E); + } + } + } + + return BS; } /// Parse function body into \p AFD or skip it for delayed parsing. @@ -6504,60 +6560,7 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) { } Scope S(this, ScopeKind::FunctionBody); - - ParserResult Body = parseAbstractFunctionBodyImpl(AFD); - if (!Body.isNull()) { - BraceStmt * BS = Body.get(); - AFD->setBodyParsed(BS); - - // If the body consists of a single expression, turn it into a return - // statement. - // - // But don't do this transformation during code completion, as the source - // may be incomplete and the type mismatch in return statement will just - // confuse the type checker. - if (!Body.hasCodeCompletion() && BS->getNumElements() == 1) { - auto Element = BS->getFirstElement(); - if (auto *stmt = Element.dyn_cast()) { - if (isa(AFD)) { - if (auto *returnStmt = dyn_cast(stmt)) { - if (!returnStmt->hasResult()) { - auto returnExpr = TupleExpr::createEmpty(Context, - SourceLoc(), - SourceLoc(), - /*implicit*/true); - returnStmt->setResult(returnExpr); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(returnExpr); - } - } - } - } else if (auto *E = Element.dyn_cast()) { - if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { - if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { - // This is an assignment. We don't want to implicitly return - // it. - return; - } - } - if (isa(AFD)) { - auto RS = new (Context) ReturnStmt(SourceLoc(), E); - BS->setFirstElement(RS); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(E); - } else if (auto *F = dyn_cast(AFD)) { - if (F->isFailable() && isa(E)) { - // If it's a nil literal, just insert return. This is the only - // legal thing to return. - auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); - BS->setFirstElement(RS); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(E); - } - } - } - } - } + (void)parseAbstractFunctionBodyImpl(AFD); } BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { @@ -6589,7 +6592,7 @@ BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { Scope TopLevelScope(this, ScopeKind::TopLevel); Scope S(this, ScopeKind::FunctionBody); - return parseAbstractFunctionBodyImpl(AFD).getPtrOrNull(); + return parseAbstractFunctionBodyImpl(AFD); } /// Parse a 'enum' declaration, returning true (and doing no token diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 7b56a1f629368..25161aabaa9ee 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -203,7 +203,7 @@ void Parser::performCodeCompletionSecondPassImpl( case CodeCompletionDelayedDeclKind::FunctionBody: { auto *AFD = cast(DC); - AFD->setBodyParsed(parseAbstractFunctionBodyImpl(AFD).getPtrOrNull()); + (void)parseAbstractFunctionBodyImpl(AFD); break; } } From c03d76291cfa03676286b01807944f793e9d8a0c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 28 Aug 2020 17:26:52 -0700 Subject: [PATCH 430/663] [ConstraintSystem] NFC: Clarify why upward propagation of literal conformances is ncessary at the moment This is NFC because only literal protocols are tracked at the moment. Forward propagate (subtype -> supertype) only literal conformance requirements since that helps solver to infer more types at parameter positions. ```swift func foo(_: String, _: T) -> T { fatalError() } func bar(_: Any?) {} func test() { bar(foo("", "")) } ``` If one of the literal arguments doesn't propagate its `ExpressibleByStringLiteral` conformance, we'd end up picking `T` with only one type `Any?` which is incorrect. This is not going to be necessary once bindings are filtered based of requirements placed on a type variable. --- lib/Sema/CSBindings.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index a82b389991788..90344be7b8154 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -56,8 +56,33 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings( auto &bindings = relatedBindings->getSecond(); - // Infer transitive protocol requirements. - llvm::copy(bindings.Protocols, std::back_inserter(Protocols)); + // FIXME: This is a workaround necessary because solver doesn't filter + // bindings based on protocol requirements placed on a type variable. + // + // Forward propagate (subtype -> supertype) only literal conformance + // requirements since that helps solver to infer more types at + // parameter positions. + // + // \code + // func foo(_: String, _: T) -> T { + // fatalError() + // } + // + // func bar(_: Any?) {} + // + // func test() { + // bar(foo("", "")) + // } + // \endcode + // + // If one of the literal arguments doesn't propagate its + // `ExpressibleByStringLiteral` conformance, we'd end up picking + // `T` with only one type `Any?` which is incorrect. + llvm::copy_if(bindings.Protocols, std::back_inserter(Protocols), + [](const Constraint *protocol) { + return protocol->getKind() == + ConstraintKind::LiteralConformsTo; + }); // Infer transitive defaults. llvm::copy(bindings.Defaults, std::back_inserter(Defaults)); From ebc03a1805eb9e2c8c6b6315dae10872095c49f3 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 28 Aug 2020 17:39:21 -0700 Subject: [PATCH 431/663] [CSBindings] NFC: Remove dead condition leftover from Swift version 3 support --- lib/Sema/CSBindings.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 90344be7b8154..5f324d7579e64 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -931,15 +931,7 @@ bool ConstraintSystem::PotentialBindings::infer( case ConstraintKind::ConformsTo: case ConstraintKind::SelfObjectOfProtocol: - // Swift 3 allowed the use of default types for normal conformances - // to expressible-by-literal protocols. - if (cs.getASTContext().LangOpts.EffectiveLanguageVersion[0] >= 4) - return false; - - if (!constraint->getSecondType()->is()) - return false; - - LLVM_FALLTHROUGH; + return false; case ConstraintKind::LiteralConformsTo: { // Record constraint where protocol requirement originated From 172c4be02d3c582235cf256103bbb3d7af914a79 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Sat, 29 Aug 2020 02:38:42 +0100 Subject: [PATCH 432/663] [Sema] Diagnose use of ambiguous property wrappers (#33688) --- include/swift/AST/DiagnosticsCommon.def | 14 ++++++ include/swift/AST/DiagnosticsParse.def | 2 - lib/AST/NameLookup.cpp | 47 ++++++++++++++++++++ lib/Sema/TypeCheckAttr.cpp | 11 ----- test/NameLookup/Inputs/custom_attrs_A.swift | 13 ++++++ test/NameLookup/Inputs/custom_attrs_B.swift | 13 ++++++ test/NameLookup/custom_attrs_ambiguous.swift | 21 +++++++++ 7 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 test/NameLookup/Inputs/custom_attrs_A.swift create mode 100644 test/NameLookup/Inputs/custom_attrs_B.swift create mode 100644 test/NameLookup/custom_attrs_ambiguous.swift diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index f4c39ce036d06..72d8d64bbecb7 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -188,5 +188,19 @@ ERROR(scanner_find_cycle, none, ERROR(scanner_arguments_invalid, none, "dependencies scanner cannot be configured with arguments: '%0'", (StringRef)) +//------------------------------------------------------------------------------ +// MARK: custom attribute diagnostics +//------------------------------------------------------------------------------ + +ERROR(ambiguous_custom_attribute_ref,none, + "ambiguous use of attribute %0", (Identifier)) +NOTE(ambiguous_custom_attribute_ref_fix,none, + "use '%0.' to reference the attribute %1 in module %2", + (StringRef, Identifier, Identifier)) +NOTE(found_attribute_candidate,none, + "found this attribute", ()) +ERROR(unknown_attribute,none, + "unknown attribute '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 6c7f4e6533b04..3a278eb7dea14 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1324,8 +1324,6 @@ ERROR(replace_equal_with_colon_for_value,none, "'=' has been replaced with ':' in attribute arguments", ()) ERROR(expected_attribute_name,none, "expected an attribute name", ()) -ERROR(unknown_attribute,none, - "unknown attribute '%0'", (StringRef)) ERROR(unexpected_lparen_in_attribute,none, "unexpected '(' in attribute '%0'", (StringRef)) ERROR(duplicate_attribute,none, diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index b581137926415..7ef21cadcb205 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -2434,6 +2434,53 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator, } } + // If we have more than one attribute declaration, we have an ambiguity. + // So, emit an ambiguity diagnostic. + if (auto typeRepr = attr->getTypeRepr()) { + if (nominals.size() > 1) { + SmallVector ambiguousCandidates; + // Filter out declarations that cannot be attributes. + for (auto decl : nominals) { + if (isa(decl)) { + continue; + } + ambiguousCandidates.push_back(decl); + } + if (ambiguousCandidates.size() > 1) { + auto attrName = nominals.front()->getName(); + ctx.Diags.diagnose(typeRepr->getLoc(), + diag::ambiguous_custom_attribute_ref, attrName); + for (auto candidate : ambiguousCandidates) { + ctx.Diags.diagnose(candidate->getLoc(), + diag::found_attribute_candidate); + // If the candidate is a top-level attribute, let's suggest + // adding module name to resolve the ambiguity. + if (candidate->getDeclContext()->isModuleScopeContext()) { + auto moduleName = candidate->getParentModule()->getName(); + ctx.Diags + .diagnose(typeRepr->getLoc(), + diag::ambiguous_custom_attribute_ref_fix, + moduleName.str(), attrName, moduleName) + .fixItInsert(typeRepr->getLoc(), moduleName.str().str() + "."); + } + } + return nullptr; + } + } + } + + // There is no nominal type with this name, so complain about this being + // an unknown attribute. + std::string typeName; + if (auto typeRepr = attr->getTypeRepr()) { + llvm::raw_string_ostream out(typeName); + typeRepr->print(out); + } else { + typeName = attr->getType().getString(); + } + + ctx.Diags.diagnose(attr->getLocation(), diag::unknown_attribute, typeName); + return nullptr; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 94478abf4f50f..df4080e85a1ba 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2901,18 +2901,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { auto nominal = evaluateOrDefault( Ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); - // If there is no nominal type with this name, complain about this being - // an unknown attribute. if (!nominal) { - std::string typeName; - if (auto typeRepr = attr->getTypeRepr()) { - llvm::raw_string_ostream out(typeName); - typeRepr->print(out); - } else { - typeName = attr->getType().getString(); - } - - diagnose(attr->getLocation(), diag::unknown_attribute, typeName); attr->setInvalid(); return; } diff --git a/test/NameLookup/Inputs/custom_attrs_A.swift b/test/NameLookup/Inputs/custom_attrs_A.swift new file mode 100644 index 0000000000000..c8035b4fa167e --- /dev/null +++ b/test/NameLookup/Inputs/custom_attrs_A.swift @@ -0,0 +1,13 @@ +@propertyWrapper +public struct Wrapper { + public var wrappedValue: Value + + public init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } +} + +@_functionBuilder +public struct Builder { + static func buildBlock(_ component: T) -> T { component } +} diff --git a/test/NameLookup/Inputs/custom_attrs_B.swift b/test/NameLookup/Inputs/custom_attrs_B.swift new file mode 100644 index 0000000000000..c8035b4fa167e --- /dev/null +++ b/test/NameLookup/Inputs/custom_attrs_B.swift @@ -0,0 +1,13 @@ +@propertyWrapper +public struct Wrapper { + public var wrappedValue: Value + + public init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } +} + +@_functionBuilder +public struct Builder { + static func buildBlock(_ component: T) -> T { component } +} diff --git a/test/NameLookup/custom_attrs_ambiguous.swift b/test/NameLookup/custom_attrs_ambiguous.swift new file mode 100644 index 0000000000000..b549e34e273ba --- /dev/null +++ b/test/NameLookup/custom_attrs_ambiguous.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -I %t -o %t %S/Inputs/custom_attrs_A.swift +// RUN: %target-swift-frontend -emit-module -I %t -o %t %S/Inputs/custom_attrs_B.swift +// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t %s +import custom_attrs_A +import custom_attrs_B + +// SR-13470 + +struct Test { + @Wrapper var x: Int = 17 + // expected-error@-1 {{ambiguous use of attribute 'Wrapper'}} + // expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Wrapper' in module 'custom_attrs_A'}} {{4-4=custom_attrs_A.}} + // expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Wrapper' in module 'custom_attrs_B'}} {{4-4=custom_attrs_B.}} + + init(@Builder closure: () -> Int) {} + // expected-error@-1 {{ambiguous use of attribute 'Builder'}} + // expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Builder' in module 'custom_attrs_A'}} {{9-9=custom_attrs_A.}} + // expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Builder' in module 'custom_attrs_B'}} {{9-9=custom_attrs_B.}} +} + From 7a6f84dc644607114237d85571d5a747c13bca71 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Fri, 28 Aug 2020 20:50:20 -0700 Subject: [PATCH 433/663] When building standalone stdlib, explicitly use C/C++ compilers from NATIVE_CLANG_TOOLS_PATH (#33675) --- utils/build-script-impl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/build-script-impl b/utils/build-script-impl index 1e80510fa7ad2..4c4d499371b9a 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1407,6 +1407,13 @@ for host in "${ALL_HOSTS[@]}"; do fi fi + if [[ "${NATIVE_CLANG_TOOLS_PATH}" ]] ; then + common_cmake_options_host+=( + -DCMAKE_C_COMPILER="${NATIVE_CLANG_TOOLS_PATH}/clang" + -DCMAKE_CXX_COMPILER="${NATIVE_CLANG_TOOLS_PATH}/clang++" + ) + fi + llvm_cmake_options=( "${llvm_cmake_options[@]}" -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" From 73f427369fc7ec1c7e13ae91aabf0a0829e3d22e Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Fri, 28 Aug 2020 20:50:47 -0700 Subject: [PATCH 434/663] Mark Reflection_jit.swift as UNSUPPORTED for standalone stdlib builds (#33682) --- test/stdlib/Reflection_jit.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/stdlib/Reflection_jit.swift b/test/stdlib/Reflection_jit.swift index c36b6b6e8cc9f..8704ba6069ceb 100644 --- a/test/stdlib/Reflection_jit.swift +++ b/test/stdlib/Reflection_jit.swift @@ -2,3 +2,8 @@ // RUN: %target-jit-run -parse-stdlib %S/Reflection.swift -- %S/Inputs/shuffle.jpg | %FileCheck %S/Reflection.swift // REQUIRES: swift_interpreter + +// Only run this test when we build host tools (e.g. bin/swift-frontend), avoid running it for standalone stdlib builds. +// Standalone stdlib builds use downloadable toolchains from swift.org, which are codesigned in a way that doesn't let +// the interpreter process (swift-frontend) dynamically load locally-built modules (libswiftCore). +// REQUIRES: swift_tools_extra From dbd16d2e05108bc922ab87fc40f2a0b7891ea5e9 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Fri, 28 Aug 2020 18:56:17 -0700 Subject: [PATCH 435/663] swift_build_sdk_interfaces.py: adjust output directory path to an SDK-versioned directory When clients specify an output directory without SDK version, the script will change the input so we emit all prebuilt module caches into SDK-versioned directories without modifying the client side. rdar://67951012 --- utils/swift_build_sdk_interfaces.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/utils/swift_build_sdk_interfaces.py b/utils/swift_build_sdk_interfaces.py index 900bae30064e0..c8381193a9bd4 100755 --- a/utils/swift_build_sdk_interfaces.py +++ b/utils/swift_build_sdk_interfaces.py @@ -354,6 +354,14 @@ def process_module_files(pool, module_files): return overall_exit_status +def getSDKVersion(sdkroot): + settingPath = os.path.join(sdkroot, 'SDKSettings.json') + with open(settingPath) as json_file: + data = json.load(json_file) + return data['Version'] + fatal("Failed to get SDK version from: " + settingPath) + + def main(): global args, shared_output_lock parser = create_parser() @@ -373,6 +381,12 @@ def main(): if not os.path.isdir(args.sdk): fatal("invalid SDK: " + args.sdk) + # if the given output dir ends with 'prebuilt-modules', we should + # append the SDK version number so all modules will built into + # the SDK-versioned sub-directory. + if os.path.basename(args.output_dir) == 'prebuilt-modules': + args.output_dir = os.path.join(args.output_dir, getSDKVersion(args.sdk)) + xfails = () if args.ignore_non_stdlib_failures: if args.xfails: From 6a20263e69be0025ac89b14553c772bfe2f415b2 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 29 Aug 2020 13:18:32 +0100 Subject: [PATCH 436/663] Request WASI in `webassembly-macos-target` preset --- utils/build-presets.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index fa4a6b9a65501..29b6fbf70d46e 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2619,6 +2619,7 @@ extra-cmake-options= -DWASI_ICU_MD5:STRING="25943864ebbfff15cf5aee8d9d5cc4d7" -DSWIFT_PRIMARY_VARIANT_SDK:STRING=WASI -DSWIFT_PRIMARY_VARIANT_ARCH:STRING=wasm32 + -DSWIFT_SDKS='WASI' -DSWIFT_OSX_x86_64_ICU_STATICLIB=TRUE -DSWIFT_BUILD_SOURCEKIT=FALSE -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE From 198687018cbeb52e225c5acac7c72661c12dee80 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Sat, 29 Aug 2020 08:06:09 -0700 Subject: [PATCH 437/663] [IDE] Fix typo to address unused warning (NFC) --- lib/IDE/ExprContextAnalysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 96f0b2126ce09..904f42a949f24 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -104,7 +104,7 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { } else if (auto *defaultArg = dyn_cast(DC)) { if (auto *AFD = dyn_cast(defaultArg->getParent())) { auto *Param = AFD->getParameters()->get(defaultArg->getIndex()); - (void*)Param->getTypeCheckedDefaultExpr(); + (void)Param->getTypeCheckedDefaultExpr(); } } break; From c34212aa20019141f4bccd0f2cb7fc0ffe217303 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 28 Aug 2020 20:00:21 -0700 Subject: [PATCH 438/663] Turn on Verbose Output For Test --- validation-test/BuildSystem/skip-local-build.test-sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validation-test/BuildSystem/skip-local-build.test-sh b/validation-test/BuildSystem/skip-local-build.test-sh index b658957c70a85..36657e3d6fa37 100644 --- a/validation-test/BuildSystem/skip-local-build.test-sh +++ b/validation-test/BuildSystem/skip-local-build.test-sh @@ -1,8 +1,8 @@ # REQUIRES: standalone_build # -# RUN: %swift_src_root/utils/build-script --dump-config --skip-local-build 2>&1 | %FileCheck %s -check-prefix=CONFIG +# RUN: %swift_src_root/utils/build-script --dump-config --skip-local-build 2>&1 | %FileCheck %s -check-prefix=CONFIG --dump-input=always # CONFIG: "skip_local_build": true -# RUN: %swift_src_root/utils/build-script --dry-run --verbose-build --skip-local-build 2>&1 | %FileCheck %s -check-prefix=DRY +# RUN: %swift_src_root/utils/build-script --dry-run --verbose-build --skip-local-build 2>&1 | %FileCheck %s -check-prefix=DRY --dump-input=always # DRY: build-script-impl # DRY-SAME: --skip-local-build From 26bac33c5987f6db86cdc5f7795b892af428ad3a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 29 Aug 2020 18:14:23 +0100 Subject: [PATCH 439/663] Fix `wait` signature in `MutexWASI.cpp` --- stdlib/public/runtime/MutexWASI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/public/runtime/MutexWASI.cpp b/stdlib/public/runtime/MutexWASI.cpp index 6288ecce03449..e62f54c107483 100644 --- a/stdlib/public/runtime/MutexWASI.cpp +++ b/stdlib/public/runtime/MutexWASI.cpp @@ -20,6 +20,6 @@ using namespace swift; -void ConditionPlatformHelper::wait(void* &condition, - void* &mutex) {} +void ConditionPlatformHelper::wait(ConditionHandle &condition, + MutexHandle &mutex) {} #endif From a412e48065dece9681451127504d20ccdc2065d7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 29 Aug 2020 11:09:54 -0700 Subject: [PATCH 440/663] Revert "Add A Reproducer For rdar://48443680" This reverts commit 57f2944aad1d08d9bbd530a8534e52895c783eb1. --- .../ClangImporter/ClangImporterTests.cpp | 107 +----------------- 1 file changed, 1 insertion(+), 106 deletions(-) diff --git a/unittests/ClangImporter/ClangImporterTests.cpp b/unittests/ClangImporter/ClangImporterTests.cpp index 4068678fd8433..e353fba57745f 100644 --- a/unittests/ClangImporter/ClangImporterTests.cpp +++ b/unittests/ClangImporter/ClangImporterTests.cpp @@ -6,10 +6,6 @@ #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangImporterOptions.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/FileSystemOptions.h" -#include "clang/Basic/FileSystemStatCache.h" -#include "clang/Frontend/CompilerInstance.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -58,6 +54,7 @@ TEST(ClangImporterTest, emitPCHInMemory) { // Create the includes. std::string include = createFilename(temp, "include"); ASSERT_FALSE(llvm::sys::fs::create_directory(include)); + options.ExtraArgs.emplace_back("-nosysteminc"); options.ExtraArgs.emplace_back((llvm::Twine("-I") + include).str()); ASSERT_FALSE(emitFileWithContents(include, "module.modulemap", "module A {\n" @@ -91,105 +88,3 @@ TEST(ClangImporterTest, emitPCHInMemory) { ASSERT_FALSE(emitFileWithContents(PCH, "garbage")); ASSERT_TRUE(importer->canReadPCH(PCH)); } - -class ForgetfulStatCache : public clang::FileSystemStatCache { -private: - std::unique_ptr RealStatCache; - -public: - ForgetfulStatCache() { - RealStatCache = std::make_unique(); - } - ~ForgetfulStatCache() = default; - - std::error_code getStat(StringRef Path, llvm::vfs::Status &Status, - bool isFile, - std::unique_ptr *F, - llvm::vfs::FileSystem &FS) override { - if (llvm::sys::path::extension(Path) == ".pcm") { - const auto UID = llvm::sys::fs::UniqueID(1, std::numeric_limits::max()); - Status = llvm::vfs::Status(Path, UID, - /*MTime*/{}, /*User*/0, /*Group*/0, - /*Size*/0, - llvm::sys::fs::file_type::regular_file, - llvm::sys::fs::perms::all_all); - return std::error_code(); - } - - return clang::FileSystemStatCache::get(Path, Status, isFile, F, - RealStatCache.get(), FS); - } -}; - -TEST(ClangImporterTest, missingSubmodule) { - // Create a temporary cache on disk and clean it up at the end. - ClangImporterOptions options; - SmallString<256> temp; - ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory( - "ClangImporterTest.missingSubmodule", temp)); - SWIFT_DEFER { llvm::sys::fs::remove_directories(temp); }; - - // Create a cache subdirectory for the modules and PCH. - std::string cache = createFilename(temp, "cache"); - ASSERT_FALSE(llvm::sys::fs::create_directory(cache)); - options.ModuleCachePath = cache; - options.PrecompiledHeaderOutputDir = cache; - - // Create the includes. - std::string include1 = createFilename(temp, "include1"); - ASSERT_FALSE(llvm::sys::fs::create_directory(include1)); - - std::string include2 = createFilename(temp, "include2"); - ASSERT_FALSE(llvm::sys::fs::create_directory(include2)); - - options.ExtraArgs.emplace_back((llvm::Twine("-I") + include1).str()); - options.ExtraArgs.emplace_back((llvm::Twine("-I") + include2).str()); - options.ExtraArgs.emplace_back("-DEXTRA_C_DEFINE=2"); - - ASSERT_FALSE(emitFileWithContents(include1, "module.modulemap", - "module CLib1 {\n" - " umbrella header \"" + include1 + "/Clib1.h\"\n" - " export * \n" - "}\n" - "module CLib2 {\n" - " umbrella header \"" + include2 + "/Clib2.h\"\n" - " export * \n" - "}\n")); - ASSERT_FALSE(emitFileWithContents(include1, "CLib1.h", - "#if !defined(EXTRA_C_DEFINE) || EXTRA_C_DEFINE != 2\n" - "#error \"unexpected compiler flags\"\n" - "#endif\n" - "void foo(void);\n")); - ASSERT_FALSE(emitFileWithContents(include2, "CLib2.h", - "#if !defined(EXTRA_C_DEFINE) || EXTRA_C_DEFINE != 2\n" - "#error \"unexpected compiler flags\"\n" - "#endif\n" - "void foo(void);\n")); - - // Set up the importer. - swift::LangOptions langOpts; - langOpts.Target = llvm::Triple("x86_64", "apple", "darwin"); - swift::TypeCheckerOptions typeckOpts; - INITIALIZE_LLVM(); - swift::SearchPathOptions searchPathOpts; - swift::SourceManager sourceMgr; - swift::DiagnosticEngine diags(sourceMgr); - std::unique_ptr context( - ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags)); - auto importer = ClangImporter::create(*context, options); - - // Install a stats cache that conveniently "forgets" that PCMs have different - // underlying FileEntry values. - importer->getClangInstance() - .getFileManager() - .setStatCache(std::make_unique()); - - context->addModuleLoader(std::move(importer)); - - auto CLib1 = context->getIdentifier("CLib1"); - auto CLib2 = context->getIdentifier("CLib2"); - // The first load succeeds and primes the ModuleManager with PCM data. - (void)context->getModule({ Located{ CLib1, {} } }); - // The second load fails because we collide in the ModuleManager. - ASSERT_TRUE(context->getModule({ Located{ CLib2, {} } }) == nullptr); -} From 907b89c8f7bbff080b63b10c4da627f49c561b60 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Sat, 29 Aug 2020 11:14:57 -0700 Subject: [PATCH 441/663] [docs] Clarify wording around adding new associatedtypes to protocols. --- docs/LibraryEvolution.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/LibraryEvolution.rst b/docs/LibraryEvolution.rst index e2813f4567fce..dac3495fe893a 100644 --- a/docs/LibraryEvolution.rst +++ b/docs/LibraryEvolution.rst @@ -578,7 +578,9 @@ There are very few safe changes to make to protocols and their members: - The ``@discardableResult`` and ``@warn_unqualified_access`` attributes may be added to or removed from a function requirement. - A new ``associatedtype`` requirement may be added (with the appropriate - availability), as long as it has a default implementation. + availability), as long as it has a default implementation. If the protocol + did not have one or more ``associatedtype`` requirements before the change, + then this is a `binary-compatible source-breaking change`. - A new non-type requirement may be added (with the appropriate availability), as long as it has an unconstrained default implementation. If the requirement uses ``Self`` and the protocol has no other requirements using ``Self`` and From c877ee6c64e9541ea43f1814432bf6feda970dde Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 29 Aug 2020 20:31:56 +0100 Subject: [PATCH 442/663] Fix Foundation install path in build-foundation.sh --- utils/webassembly/build-foundation.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/webassembly/build-foundation.sh b/utils/webassembly/build-foundation.sh index 6d15e0ba5b216..88fcee67a2fa4 100755 --- a/utils/webassembly/build-foundation.sh +++ b/utils/webassembly/build-foundation.sh @@ -28,6 +28,6 @@ ninja -v install # On Linux though there's no system CoreFoundation, its headers have to be shipped # in the installable archive and serve for both host and target. if [[ "$(uname)" == "Darwin" ]]; then - mv $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation \ + mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation fi \ No newline at end of file From 0869b519cdb15c8a1dfad09271c9e1ad19defffd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 29 Aug 2020 17:19:49 -0700 Subject: [PATCH 443/663] Revert "Fallback to building Cmake from source on all platforms, not just Linux (#33543)" This reverts commit 539b241bf2b36b7d7e9362c30d7a39d1978bad38. --- utils/swift_build_support/swift_build_support/cmake.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/swift_build_support/swift_build_support/cmake.py b/utils/swift_build_support/swift_build_support/cmake.py index 5ef74e0cf5ee4..85a97dfa747e2 100644 --- a/utils/swift_build_support/swift_build_support/cmake.py +++ b/utils/swift_build_support/swift_build_support/cmake.py @@ -18,6 +18,7 @@ from __future__ import absolute_import, unicode_literals import os +import platform import re from numbers import Number @@ -255,6 +256,9 @@ def build_cmake(self, source_root, build_root): # the source and build the source if necessary. Returns the path to the # cmake binary. def check_cmake_version(self, source_root, build_root): + if platform.system() != 'Linux': + return + cmake_source_dir = os.path.join(source_root, 'cmake') # If the source is not checked out then don't attempt to build cmake. if not os.path.isdir(cmake_source_dir): From 161fa16cf821a23bab2b1ad57dc1a05fde404e61 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 29 Aug 2020 17:20:49 -0700 Subject: [PATCH 444/663] Revert "Turn on Verbose Output For Test" This reverts commit c34212aa20019141f4bccd0f2cb7fc0ffe217303. --- validation-test/BuildSystem/skip-local-build.test-sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validation-test/BuildSystem/skip-local-build.test-sh b/validation-test/BuildSystem/skip-local-build.test-sh index 36657e3d6fa37..b658957c70a85 100644 --- a/validation-test/BuildSystem/skip-local-build.test-sh +++ b/validation-test/BuildSystem/skip-local-build.test-sh @@ -1,8 +1,8 @@ # REQUIRES: standalone_build # -# RUN: %swift_src_root/utils/build-script --dump-config --skip-local-build 2>&1 | %FileCheck %s -check-prefix=CONFIG --dump-input=always +# RUN: %swift_src_root/utils/build-script --dump-config --skip-local-build 2>&1 | %FileCheck %s -check-prefix=CONFIG # CONFIG: "skip_local_build": true -# RUN: %swift_src_root/utils/build-script --dry-run --verbose-build --skip-local-build 2>&1 | %FileCheck %s -check-prefix=DRY --dump-input=always +# RUN: %swift_src_root/utils/build-script --dry-run --verbose-build --skip-local-build 2>&1 | %FileCheck %s -check-prefix=DRY # DRY: build-script-impl # DRY-SAME: --skip-local-build From fcf398a17b4e53deef12019800dd95fdc582e2aa Mon Sep 17 00:00:00 2001 From: David Ungar Date: Sat, 29 Aug 2020 19:36:04 -0700 Subject: [PATCH 445/663] Don't crash on a bad -j input --- test/Driver/badJ.swift | 2 ++ tools/driver/driver.cpp | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 test/Driver/badJ.swift diff --git a/test/Driver/badJ.swift b/test/Driver/badJ.swift new file mode 100644 index 0000000000000..9f27b6735d52f --- /dev/null +++ b/test/Driver/badJ.swift @@ -0,0 +1,2 @@ +// RUN: not %swiftc_driver %S/../Inputs/empty.swift -jsnort 2>&1 | %FileCheck %s +// CHECK-NOT: Stack dump diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index ff189f773ab28..4ad79a461cdff 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -191,6 +191,8 @@ static int run_driver(StringRef ExecName, if (C) { std::unique_ptr TQ = TheDriver.buildTaskQueue(*C); + if (!TQ) + return 1; return C->performJobs(std::move(TQ)); } From dcc27ea819f8a85a4331f7b6b00661c6d47cd230 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 28 Aug 2020 19:15:17 -0400 Subject: [PATCH 446/663] Sema: Fix failure to emit diagnostic with some invalid member type references There were two problems here: - isUnsupportedMemberTypeReference() checked if the immediate parent type was an unbound generic type, but did not check for the parent of the parent, etc. - The caller of isUnsupportedMemberTypeReference() had to re-check the various invalid conditions to determine what diagnostic to emit, and if none of those conditions matched it would just return an ErrorType without emitting a diagnostic. Fix both of these by having isUnsupportedMemberTypeReference() return an enum indicating what went wrong, and handle more cases. Fixes . --- lib/Sema/TypeCheckDeclPrimary.cpp | 8 +-- lib/Sema/TypeCheckNameLookup.cpp | 25 ++++----- lib/Sema/TypeCheckType.cpp | 68 +++++++++++++++--------- lib/Sema/TypeChecker.h | 11 +++- test/Generics/unbound.swift | 17 ++++++ test/IDE/print_ast_tc_decls_errors.swift | 4 +- test/decl/nested/protocol.swift | 3 +- test/decl/overload.swift | 1 - 8 files changed, 90 insertions(+), 47 deletions(-) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 95f137573b909..2e9a3c01bf1ab 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1853,9 +1853,11 @@ class DeclChecker : public DeclVisitor { if (auto rawTy = ED->getRawType()) { // The raw type must be one of the blessed literal convertible types. if (!computeAutomaticEnumValueKind(ED)) { - DE.diagnose(ED->getInherited().front().getSourceRange().Start, - diag::raw_type_not_literal_convertible, rawTy); - ED->getInherited().front().setType(ErrorType::get(getASTContext())); + if (!rawTy->is()) { + DE.diagnose(ED->getInherited().front().getSourceRange().Start, + diag::raw_type_not_literal_convertible, rawTy); + ED->getInherited().front().setType(ErrorType::get(getASTContext())); + } } // We need at least one case to have a raw value. diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 1cddaedd4f562..6305169b4156d 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -338,7 +338,8 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, return result; } -bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { +TypeChecker::UnsupportedMemberTypeAccessKind +TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { // We don't allow lookups of a non-generic typealias of an unbound // generic type, because we have no way to model such a type in the // AST. @@ -346,10 +347,7 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { // For generic typealiases, the typealias itself has an unbound // generic form whose parent type can be another unbound generic // type. - // - // FIXME: Could lift this restriction once we have sugared - // "member types". - if (type->is()) { + if (type->hasUnboundGenericType()) { // Generic typealiases can be accessed with an unbound generic // base, since we represent the member type as an unbound generic // type. @@ -359,12 +357,12 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { if (auto *aliasDecl = dyn_cast(typeDecl)) { if (!aliasDecl->isGeneric() && aliasDecl->getUnderlyingType()->hasTypeParameter()) { - return true; + return UnsupportedMemberTypeAccessKind::TypeAliasOfUnboundGeneric; } } if (isa(typeDecl)) - return true; + return UnsupportedMemberTypeAccessKind::AssociatedTypeOfUnboundGeneric; } if (type->isExistentialType() && @@ -374,15 +372,13 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) { if (auto *aliasDecl = dyn_cast(typeDecl)) { if (aliasDecl->getUnderlyingType()->getCanonicalType() ->hasTypeParameter()) - return true; - } else { - // Don't allow lookups of other nested types of an existential type, - // because there is no way to represent such types. - return true; + return UnsupportedMemberTypeAccessKind::TypeAliasOfExistential; + } else if (isa(typeDecl)) { + return UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential; } } - return false; + return UnsupportedMemberTypeAccessKind::None; } LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, @@ -419,7 +415,8 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, continue; } - if (isUnsupportedMemberTypeAccess(type, typeDecl)) { + if (isUnsupportedMemberTypeAccess(type, typeDecl) + != TypeChecker::UnsupportedMemberTypeAccessKind::None) { auto memberType = typeDecl->getDeclaredInterfaceType(); // Add the type to the result set, so that we can diagnose the diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index a3845b07b62ae..6e3dc8a61aa4e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -945,21 +945,32 @@ Type TypeChecker::applyUnboundGenericArguments(GenericTypeDecl *decl, /// Diagnose a use of an unbound generic type. static void diagnoseUnboundGenericType(Type ty, SourceLoc loc) { - auto unbound = ty->castTo(); - { - auto &ctx = ty->getASTContext(); - InFlightDiagnostic diag = ctx.Diags.diagnose(loc, - diag::generic_type_requires_arguments, ty); - if (auto *genericD = unbound->getDecl()) { + auto &ctx = ty->getASTContext(); + if (auto unbound = ty->getAs()) { + auto *decl = unbound->getDecl(); + { + InFlightDiagnostic diag = ctx.Diags.diagnose(loc, + diag::generic_type_requires_arguments, ty); SmallString<64> genericArgsToAdd; if (TypeChecker::getDefaultGenericArgumentsString(genericArgsToAdd, - genericD)) + decl)) diag.fixItInsertAfter(loc, genericArgsToAdd); } + + decl->diagnose(diag::kind_declname_declared_here, + DescriptiveDeclKind::GenericType, + decl->getName()); + } else { + ty.findIf([&](Type t) -> bool { + if (auto unbound = t->getAs()) { + ctx.Diags.diagnose(loc, + diag::generic_type_requires_arguments, t); + return true; + } + + return false; + }); } - unbound->getDecl()->diagnose(diag::kind_declname_declared_here, - DescriptiveDeclKind::GenericType, - unbound->getDecl()->getName()); } // Produce a diagnostic if the type we referenced was an @@ -1417,22 +1428,29 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution, auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType, AssociatedTypeDecl *inferredAssocType) { - // Diagnose invalid cases. - if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) { - if (!options.contains(TypeResolutionFlags::SilenceErrors)) { - if (parentTy->is()) - diagnoseUnboundGenericType(parentTy, parentRange.End); - else if (parentTy->isExistentialType() && - isa(member)) { - diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol, - comp->getNameRef()); - } else if (parentTy->isExistentialType() && - isa(member)) { - diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol, - comp->getNameRef()); - } - } + if (options.contains(TypeResolutionFlags::SilenceErrors)) { + if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member) + != TypeChecker::UnsupportedMemberTypeAccessKind::None) + return ErrorType::get(ctx); + } + + switch (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) { + case TypeChecker::UnsupportedMemberTypeAccessKind::None: + break; + + case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfUnboundGeneric: + case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfUnboundGeneric: + diagnoseUnboundGenericType(parentTy, parentRange.End); + return ErrorType::get(ctx); + + case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfExistential: + diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol, + comp->getNameRef()); + return ErrorType::get(ctx); + case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential: + diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol, + comp->getNameRef()); return ErrorType::get(ctx); } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index ddc5711d4ed5e..9881b477ddd38 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -927,9 +927,18 @@ PrecedenceGroupDecl *lookupPrecedenceGroupForInfixOperator(DeclContext *dc, PrecedenceGroupLookupResult lookupPrecedenceGroup(DeclContext *dc, Identifier name, SourceLoc nameLoc); +enum class UnsupportedMemberTypeAccessKind : uint8_t { + None, + TypeAliasOfUnboundGeneric, + TypeAliasOfExistential, + AssociatedTypeOfUnboundGeneric, + AssociatedTypeOfExistential +}; + /// Check whether the given declaration can be written as a /// member of the given base type. -bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); +UnsupportedMemberTypeAccessKind +isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); /// @} diff --git a/test/Generics/unbound.swift b/test/Generics/unbound.swift index aed3469e8f6b5..8f57d930ee13c 100644 --- a/test/Generics/unbound.swift +++ b/test/Generics/unbound.swift @@ -74,3 +74,20 @@ struct X1 { func bar() where T: X2 {} } class X2 {} + +// missing check for unbound parent type +struct Outer { + struct Inner {} + + struct Middle { + typealias Inner = Outer.Middle + } +} + +func makeInner() -> Outer.Middle.Inner { + return .init() +} + +var innerProperty: Outer.Middle.Inner = makeInner() +// expected-error@-1 {{reference to generic type 'Outer' requires arguments in <...>}} + diff --git a/test/IDE/print_ast_tc_decls_errors.swift b/test/IDE/print_ast_tc_decls_errors.swift index 802c10a7dea84..4127f2cc0e034 100644 --- a/test/IDE/print_ast_tc_decls_errors.swift +++ b/test/IDE/print_ast_tc_decls_errors.swift @@ -109,11 +109,11 @@ class ClassWithInheritance9 : FooClass, BarClass, FooProtocol, BarProtocol, FooN //===--- Inheritance list in enums. //===--- -enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{raw type}} expected-error {{an enum with no cases}} +enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{an enum with no cases}} // NO-TYREPR: {{^}}enum EnumWithInheritance1 : <> {{{$}} // TYREPR: {{^}}enum EnumWithInheritance1 : FooNonExistentProtocol {{{$}} -enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{cannot find type 'BarNonExistentProtocol' in scope}} expected-error {{raw type}} expected-error {{an enum with no cases}} +enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{cannot find type 'BarNonExistentProtocol' in scope}} expected-error {{an enum with no cases}} // NO-TYREPR: {{^}}enum EnumWithInheritance2 : <>, <> {{{$}} // TYREPR: {{^}}enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {{{$}} diff --git a/test/decl/nested/protocol.swift b/test/decl/nested/protocol.swift index 2d820f9224832..2ccc15b74e9a3 100644 --- a/test/decl/nested/protocol.swift +++ b/test/decl/nested/protocol.swift @@ -51,10 +51,11 @@ protocol Racoon { } enum SillyRawEnum : SillyProtocol.InnerClass {} // expected-error {{an enum with no cases cannot declare a raw type}} -// expected-error@-1 {{raw type}} +// expected-error@-1 {{reference to generic type 'SillyProtocol.InnerClass' requires arguments in <...>}} protocol SillyProtocol { class InnerClass {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}} + // expected-note@-1 {{generic type 'InnerClass' declared here}} } // N.B. Redeclaration checks don't see this case because `protocol A` is invalid. diff --git a/test/decl/overload.swift b/test/decl/overload.swift index 07ba5b7e948eb..b769dd03c7c9e 100644 --- a/test/decl/overload.swift +++ b/test/decl/overload.swift @@ -79,7 +79,6 @@ enum mixed_redecl3 {} // expected-error {{invalid redeclaration}} // expected-note @-1 2{{found this candidate}} enum mixed_redecl3a : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}} // expected-error@-1 {{an enum with no cases cannot declare a raw type}} -// expected-error@-2 {{raw type}} class mixed_redecl3b : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}} class mixed_redecl4 {} // expected-note {{previously declared here}} From 364b7c742ca4cd61b839f552647c2f59705603e7 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 27 Aug 2020 23:23:19 -0700 Subject: [PATCH 447/663] [ownership] Refactor OwnershipLiveRange and OwnershipPhiOperand into separate files from SemanticARCOpts.cpp --- lib/SILOptimizer/SemanticARC/CMakeLists.txt | 3 +- .../SemanticARC/OwnershipLiveRange.cpp | 354 ++++++++++ .../SemanticARC/OwnershipLiveRange.h | 210 ++++++ .../SemanticARC/OwnershipPhiOperand.h | 122 ++++ .../SemanticARC/SemanticARCOpts.cpp | 652 +----------------- 5 files changed, 695 insertions(+), 646 deletions(-) create mode 100644 lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp create mode 100644 lib/SILOptimizer/SemanticARC/OwnershipLiveRange.h create mode 100644 lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt index 7ae8f36a2bbde..91b9e107c5dc8 100644 --- a/lib/SILOptimizer/SemanticARC/CMakeLists.txt +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -1,2 +1,3 @@ target_sources(swiftSILOptimizer PRIVATE - SemanticARCOpts.cpp) + SemanticARCOpts.cpp + OwnershipLiveRange.cpp) diff --git a/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp new file mode 100644 index 0000000000000..187b28e68c27b --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp @@ -0,0 +1,354 @@ +//===--- OwnershipLiveRange.cpp -------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "OwnershipLiveRange.h" +#include "OwnershipPhiOperand.h" + +using namespace swift; +using namespace swift::semanticarc; + +OwnershipLiveRange::OwnershipLiveRange(SILValue value) + : introducer(*OwnedValueIntroducer::get(value)), destroyingUses(), + ownershipForwardingUses(), unknownConsumingUses() { + assert(introducer.value.getOwnershipKind() == ValueOwnershipKind::Owned); + + SmallVector tmpDestroyingUses; + SmallVector tmpForwardingConsumingUses; + SmallVector tmpUnknownConsumingUses; + + // We know that our silvalue produces an @owned value. Look through all of our + // uses and classify them as either consuming or not. + SmallVector worklist(introducer.value->getUses()); + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + + // Skip type dependent operands. + if (op->isTypeDependent()) + continue; + + // Do a quick check that we did not add ValueOwnershipKind that are not + // owned to the worklist. + assert(op->get().getOwnershipKind() == ValueOwnershipKind::Owned && + "Added non-owned value to worklist?!"); + + auto *user = op->getUser(); + + // Ok, this constraint can take something owned as live. Assert that it + // can also accept something that is guaranteed. Any non-consuming use of + // an owned value should be able to take a guaranteed parameter as well + // (modulo bugs). We assert to catch these. + if (!op->isConsumingUse()) { + continue; + } + + // Ok, we know now that we have a consuming use. See if we have a destroy + // value, quickly up front. If we do have one, stash it and continue. + if (isa(user)) { + tmpDestroyingUses.push_back(op); + continue; + } + + // Otherwise, see if we have a forwarding value that has a single + // non-trivial operand that can accept a guaranteed value. If not, we can + // not recursively process it, so be conservative and assume that we /may + // consume/ the value, so the live range must not be eliminated. + // + // DISCUSSION: For now we do not support forwarding instructions with + // multiple non-trivial arguments since we would need to optimize all of + // the non-trivial arguments at the same time. + // + // NOTE: Today we do not support TermInsts for simplicity... we /could/ + // support it though if we need to. + auto *ti = dyn_cast(user); + if ((ti && !ti->isTransformationTerminator()) || + !isGuaranteedForwardingInst(user) || + 1 != count_if(user->getOperandValues( + true /*ignore type dependent operands*/), + [&](SILValue v) { + return v.getOwnershipKind() == + ValueOwnershipKind::Owned; + })) { + tmpUnknownConsumingUses.push_back(op); + continue; + } + + // Ok, this is a forwarding instruction whose ownership we can flip from + // owned -> guaranteed. + tmpForwardingConsumingUses.push_back(op); + + // If we have a non-terminator, just visit its users recursively to see if + // the the users force the live range to be alive. + if (!ti) { + for (SILValue v : user->getResults()) { + if (v.getOwnershipKind() != ValueOwnershipKind::Owned) + continue; + llvm::copy(v->getUses(), std::back_inserter(worklist)); + } + continue; + } + + // Otherwise, we know that we have no only a terminator, but a + // transformation terminator, so we should add the users of its results to + // the worklist. + for (auto &succ : ti->getSuccessors()) { + auto *succBlock = succ.getBB(); + + // If we do not have any arguments, then continue. + if (succBlock->args_empty()) + continue; + + for (auto *succArg : succBlock->getSILPhiArguments()) { + // If we have an any value, just continue. + if (succArg->getOwnershipKind() == ValueOwnershipKind::None) + continue; + + // Otherwise add all users of this BBArg to the worklist to visit + // recursively. + llvm::copy(succArg->getUses(), std::back_inserter(worklist)); + } + } + } + + // The order in which we append these to consumingUses matters since we assume + // their order as an invariant. This is done to ensure that we can pass off + // all of our uses or individual sub-arrays of our users without needing to + // move around memory. + llvm::copy(tmpDestroyingUses, std::back_inserter(consumingUses)); + llvm::copy(tmpForwardingConsumingUses, std::back_inserter(consumingUses)); + llvm::copy(tmpUnknownConsumingUses, std::back_inserter(consumingUses)); + + auto cUseArrayRef = llvm::makeArrayRef(consumingUses); + destroyingUses = cUseArrayRef.take_front(tmpDestroyingUses.size()); + ownershipForwardingUses = cUseArrayRef.slice( + tmpDestroyingUses.size(), tmpForwardingConsumingUses.size()); + unknownConsumingUses = cUseArrayRef.take_back(tmpUnknownConsumingUses.size()); +} + +void OwnershipLiveRange::insertEndBorrowsAtDestroys( + SILValue newGuaranteedValue, DeadEndBlocks &deadEndBlocks, + ValueLifetimeAnalysis::Frontier &scratch) { + assert(scratch.empty() && "Expected scratch to be initially empty?!"); + + // Since we are looking through forwarding uses that can accept guaranteed + // parameters, we can have multiple destroy_value along the same path. We need + // to find the post-dominating block set of these destroy value to ensure that + // we do not insert multiple end_borrow. + // + // TODO: Hoist this out? + SILInstruction *inst = introducer.value->getDefiningInstruction(); + Optional analysis; + if (!inst) { + analysis.emplace(cast(introducer.value), + getAllConsumingInsts()); + } else { + analysis.emplace(inst, getAllConsumingInsts()); + } + + // Use all consuming uses in our value lifetime analysis to ensure correctness + // in the face of unreachable code. + bool foundCriticalEdges = !analysis->computeFrontier( + scratch, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks); + (void)foundCriticalEdges; + assert(!foundCriticalEdges); + auto loc = RegularLocation::getAutoGeneratedLocation(); + while (!scratch.empty()) { + auto *insertPoint = scratch.pop_back_val(); + SILBuilderWithScope builder(insertPoint); + builder.createEndBorrow(loc, newGuaranteedValue); + } +} + +static void convertInstructionOwnership(SILInstruction *i, + ValueOwnershipKind oldOwnership, + ValueOwnershipKind newOwnership) { + // If this is a term inst, just convert all of its incoming values that are + // owned to be guaranteed. + if (auto *ti = dyn_cast(i)) { + for (auto &succ : ti->getSuccessors()) { + auto *succBlock = succ.getBB(); + + // If we do not have any arguments, then continue. + if (succBlock->args_empty()) + continue; + + for (auto *succArg : succBlock->getSILPhiArguments()) { + // If we have an any value, just continue. + if (succArg->getOwnershipKind() == oldOwnership) { + succArg->setOwnershipKind(newOwnership); + } + } + } + return; + } + + assert(i->hasResults()); + for (SILValue result : i->getResults()) { + if (auto *svi = dyn_cast(result)) { + if (svi->getOwnershipKind() == oldOwnership) { + svi->setOwnershipKind(newOwnership); + } + continue; + } + + if (auto *ofci = dyn_cast(result)) { + if (ofci->getOwnershipKind() == oldOwnership) { + ofci->setOwnershipKind(newOwnership); + } + continue; + } + + if (auto *sei = dyn_cast(result)) { + if (sei->getOwnershipKind() == oldOwnership) { + sei->setOwnershipKind(newOwnership); + } + continue; + } + + if (auto *mvir = dyn_cast(result)) { + if (mvir->getOwnershipKind() == oldOwnership) { + mvir->setOwnershipKind(newOwnership); + } + continue; + } + + llvm_unreachable("unhandled forwarding instruction?!"); + } +} + +void OwnershipLiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() && { + while (!ownershipForwardingUses.empty()) { + auto *i = ownershipForwardingUses.back()->getUser(); + ownershipForwardingUses = ownershipForwardingUses.drop_back(); + convertInstructionOwnership(i, ValueOwnershipKind::Owned, + ValueOwnershipKind::Guaranteed); + } +} + +void OwnershipLiveRange::convertToGuaranteedAndRAUW( + SILValue newGuaranteedValue, InstModCallbacks callbacks) && { + auto *value = cast(introducer.value); + while (!destroyingUses.empty()) { + auto *d = destroyingUses.back(); + destroyingUses = destroyingUses.drop_back(); + callbacks.deleteInst(d->getUser()); + } + + callbacks.eraseAndRAUWSingleValueInst(value, newGuaranteedValue); + + // Then change all of our guaranteed forwarding insts to have guaranteed + // ownership kind instead of what ever they previously had (ignoring trivial + // results); + std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); +} + +// TODO: If this is useful, move onto OwnedValueIntroducer itself? +static SILValue convertIntroducerToGuaranteed(OwnedValueIntroducer introducer) { + switch (introducer.kind) { + case OwnedValueIntroducerKind::Phi: { + auto *phiArg = cast(introducer.value); + phiArg->setOwnershipKind(ValueOwnershipKind::Guaranteed); + return phiArg; + } + case OwnedValueIntroducerKind::Struct: { + auto *si = cast(introducer.value); + si->setOwnershipKind(ValueOwnershipKind::Guaranteed); + return si; + } + case OwnedValueIntroducerKind::Tuple: { + auto *ti = cast(introducer.value); + ti->setOwnershipKind(ValueOwnershipKind::Guaranteed); + return ti; + } + case OwnedValueIntroducerKind::Copy: + case OwnedValueIntroducerKind::LoadCopy: + case OwnedValueIntroducerKind::Apply: + case OwnedValueIntroducerKind::BeginApply: + case OwnedValueIntroducerKind::TryApply: + case OwnedValueIntroducerKind::LoadTake: + case OwnedValueIntroducerKind::FunctionArgument: + case OwnedValueIntroducerKind::PartialApplyInit: + case OwnedValueIntroducerKind::AllocBoxInit: + case OwnedValueIntroducerKind::AllocRefInit: + return SILValue(); + } +} + +void OwnershipLiveRange::convertJoinedLiveRangePhiToGuaranteed( + DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, + InstModCallbacks callbacks) && { + + // First convert the phi value itself to be guaranteed. + SILValue phiValue = convertIntroducerToGuaranteed(introducer); + + // Then insert end_borrows at each of our destroys if we are consuming. We + // have to convert the phi to guaranteed first since otherwise, the ownership + // check when we create the end_borrows will trigger. + if (introducer.hasConsumingGuaranteedOperands()) { + insertEndBorrowsAtDestroys(phiValue, deadEndBlocks, scratch); + } + + // Then eliminate all of the destroys... + while (!destroyingUses.empty()) { + auto *d = destroyingUses.back(); + destroyingUses = destroyingUses.drop_back(); + callbacks.deleteInst(d->getUser()); + } + + // and change all of our guaranteed forwarding insts to have guaranteed + // ownership kind instead of what ever they previously had (ignoring trivial + // results); + std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); +} + +OwnershipLiveRange::HasConsumingUse_t +OwnershipLiveRange::hasUnknownConsumingUse(bool assumingAtFixPoint) const { + // First do a quick check if we have /any/ unknown consuming + // uses. If we do not have any, return false early. + if (unknownConsumingUses.empty()) { + return HasConsumingUse_t::No; + } + + // Ok, we do have some unknown consuming uses. If we aren't assuming we are at + // the fixed point yet, just bail. + if (!assumingAtFixPoint) { + return HasConsumingUse_t::Yes; + } + + // We do not know how to handle yet cases where an owned value is used by + // multiple phi nodes. So we bail early if unknown consuming uses is > 1. + // + // TODO: Build up phi node web. + auto *op = getSingleUnknownConsumingUse(); + if (!op) { + return HasConsumingUse_t::Yes; + } + + // Make sure our single unknown consuming use is a branch inst. If not, bail, + // this is a /real/ unknown consuming use. + if (!OwnershipPhiOperand::get(op)) { + return HasConsumingUse_t::Yes; + } + + // Otherwise, setup the phi to incoming value map mapping the block arguments + // to our introducer. + return HasConsumingUse_t::YesButAllPhiArgs; +} + +OwnershipLiveRange::DestroyingInstsRange +OwnershipLiveRange::getDestroyingInsts() const { + return DestroyingInstsRange(getDestroyingUses(), OperandToUser()); +} + +OwnershipLiveRange::ConsumingInstsRange +OwnershipLiveRange::getAllConsumingInsts() const { + return ConsumingInstsRange(consumingUses, OperandToUser()); +} diff --git a/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.h b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.h new file mode 100644 index 0000000000000..c9be71b479a3b --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnershipLiveRange.h @@ -0,0 +1,210 @@ +//===--- OwnershipLiveRange.h ---------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H +#define SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H + +#include "swift/SIL/OwnershipUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" + +namespace swift { +namespace semanticarc { + +/// This class represents an "extended live range" of an owned value. Such a +/// representation includes: +/// +/// 1. The owned introducing value. +/// 2. Any forwarding instructions that consume the introduced value +/// (transitively) and then propagate a new owned value. +/// 3. Transitive destroys on the forwarding instructions/destroys on the owned +/// introducing value. +/// 4. Any unknown consuming uses that are not understood by this code. +/// +/// This allows for this to be used to convert such a set of uses from using +/// owned ownership to using guaranteed ownership by converting the +/// destroy_value -> end_borrow and "flipping" the ownership of individual +/// forwarding instructions. +/// +/// NOTE: We do not look through "phi nodes" in the ownership graph (e.x.: real +/// phi arguments, struct, tuple). Instead we represent those as nodes in a +/// larger phi ownership web, connected via individual OwnershipLiveRange. +class LLVM_LIBRARY_VISIBILITY OwnershipLiveRange { + /// The value that we are computing the LiveRange for. Expected to be an owned + /// introducer and not to be forwarding. + OwnedValueIntroducer introducer; + + /// A vector that we store all of our uses into. + /// + /// Some properties of this array are: + /// + /// 1. It is only mutated in the constructor of LiveRange. + /// + /// 2. destroyingUses, ownershipForwardingUses, and unknownConsumingUses are + /// views into this array. We store the respective uses in the aforementioned + /// order. This is why it is important not to mutate consumingUses after we + /// construct the LiveRange since going from small -> large could invalidate + /// the uses. + SmallVector consumingUses; + + /// A list of destroy_values of the live range. + /// + /// This is just a view into consuming uses. + ArrayRef destroyingUses; + + /// A list of forwarding instructions that forward owned ownership, but that + /// are also able to be converted to guaranteed ownership. + /// + /// If we are able to eliminate this LiveRange due to it being from a + /// guaranteed value, we must flip the ownership of all of these instructions + /// to guaranteed from owned. + /// + /// NOTE: Normally only destroying or consuming uses end the live range. We + /// copy these transitive uses as well into the consumingUses array since + /// transitive uses can extend a live range up to an unreachable block without + /// ultimately being consuming. In such a situation if we did not also store + /// this into consuming uses, we would not be able to ascertain just using the + /// "consumingUses" array the true lifetime of the OwnershipLiveRange. + /// + /// Corresponds to isOwnershipForwardingInst(...). + ArrayRef ownershipForwardingUses; + + /// Consuming uses that we were not able to understand as a forwarding + /// instruction or a destroy_value. These must be passed a strongly control + /// equivalent +1 value. + ArrayRef unknownConsumingUses; + +public: + OwnershipLiveRange(SILValue value); + OwnershipLiveRange(const OwnershipLiveRange &) = delete; + OwnershipLiveRange &operator=(const OwnershipLiveRange &) = delete; + + enum class HasConsumingUse_t { + No = 0, + YesButAllPhiArgs = 1, + Yes = 2, + }; + + /// Return true if v only has invalidating uses that are destroy_value. Such + /// an owned value is said to represent a dead "live range". + /// + /// Semantically this implies that a value is never passed off as +1 to memory + /// or another function implying it can be used everywhere at +0. + HasConsumingUse_t + hasUnknownConsumingUse(bool assumingFixedPoint = false) const; + + /// Return an array ref to /all/ consuming uses. Will include all 3 sorts of + /// consuming uses: destroying uses, forwarding consuming uses, and unknown + /// forwarding instruction. + ArrayRef getAllConsumingUses() const { return consumingUses; } + + ArrayRef getDestroyingUses() const { return destroyingUses; } + +private: + struct OperandToUser; + +public: + using DestroyingInstsRange = + TransformRange, OperandToUser>; + DestroyingInstsRange getDestroyingInsts() const; + + using ConsumingInstsRange = + TransformRange, OperandToUser>; + ConsumingInstsRange getAllConsumingInsts() const; + + /// If this LiveRange has a single destroying use, return that use. Otherwise, + /// return nullptr. + Operand *getSingleDestroyingUse() const { + if (destroyingUses.size() != 1) { + return nullptr; + } + return destroyingUses.front(); + } + + /// If this LiveRange has a single unknown destroying use, return that + /// use. Otherwise, return nullptr. + Operand *getSingleUnknownConsumingUse() const { + if (unknownConsumingUses.size() != 1) { + return nullptr; + } + return unknownConsumingUses.front(); + } + + OwnedValueIntroducer getIntroducer() const { return introducer; } + + ArrayRef getOwnershipForwardingUses() const { + return ownershipForwardingUses; + } + + void convertOwnedGeneralForwardingUsesToGuaranteed() &&; + + /// A consuming operation that: + /// + /// 1. If \p insertEndBorrows is true inserts end borrows at all + /// destroying insts locations. + /// + /// 2. Deletes all destroy_values. + /// + /// 3. RAUW value with newGuaranteedValue. + /// + /// 4. Convert all of the general forwarding instructions from + /// @owned -> @guaranteed. "Like Dominoes". + /// + /// 5. Leaves all of the unknown consuming users alone. It is up to + /// the caller to handle converting their ownership. + void convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, + InstModCallbacks callbacks) &&; + + /// A consuming operation that in order: + /// + /// 1. Converts the phi argument to be guaranteed via setOwnership. + /// + /// 2. If this consumes a borrow, insert end_borrows at the relevant + /// destroy_values. + /// + /// 3. Deletes all destroy_values. + /// + /// 4. Converts all of the general forwarding instructions from @owned -> + /// @guaranteed. "Like Dominoes". + /// + /// NOTE: This leaves all of the unknown consuming users alone. It is up to + /// the caller to handle converting their ownership. + /// + /// NOTE: This routine leaves inserting begin_borrows for the incoming values + /// to the caller since those are not part of the LiveRange itself. + void convertJoinedLiveRangePhiToGuaranteed( + DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, + InstModCallbacks callbacks) &&; + + /// Given a new guaranteed value, insert end_borrow for the newGuaranteedValue + /// at all of our destroy_values in prepration for converting from owned to + /// guaranteed. + /// + /// This is used when converting load [copy] -> load_borrow. + void insertEndBorrowsAtDestroys(SILValue newGuaranteedValue, + DeadEndBlocks &deadEndBlocks, + ValueLifetimeAnalysis::Frontier &scratch); +}; + +struct OwnershipLiveRange::OperandToUser { + OperandToUser() {} + + SILInstruction *operator()(const Operand *use) const { + auto *nonConstUse = const_cast(use); + return nonConstUse->getUser(); + } +}; + +} // namespace semanticarc +} // namespace swift + +#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H diff --git a/lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h b/lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h new file mode 100644 index 0000000000000..169eb9859bea8 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h @@ -0,0 +1,122 @@ +//===--- OwnershipPhiOperand.h --------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPPHIOPERAND_H +#define SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPPHIOPERAND_H + +#include "swift/Basic/STLExtras.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILUndef.h" +#include "swift/SIL/SILValue.h" + +namespace swift { +namespace semanticarc { + +/// The operand of a "phi" in the induced ownership graph of a def-use graph. +/// +/// Some examples: br, struct, tuple. +class LLVM_LIBRARY_VISIBILITY OwnershipPhiOperand { +public: + enum Kind { + Branch, + Struct, + Tuple, + }; + +private: + Operand *op; + + OwnershipPhiOperand(Operand *op) : op(op) {} + +public: + static Optional get(const Operand *op) { + switch (op->getUser()->getKind()) { + case SILInstructionKind::BranchInst: + case SILInstructionKind::StructInst: + case SILInstructionKind::TupleInst: + return {{const_cast(op)}}; + default: + return None; + } + } + + Kind getKind() const { + switch (op->getUser()->getKind()) { + case SILInstructionKind::BranchInst: + return Kind::Branch; + case SILInstructionKind::StructInst: + return Kind::Struct; + case SILInstructionKind::TupleInst: + return Kind::Tuple; + default: + llvm_unreachable("unhandled case?!"); + } + } + + Operand *getOperand() const { return op; } + SILValue getValue() const { return op->get(); } + SILType getType() const { return op->get()->getType(); } + + unsigned getOperandNumber() const { return op->getOperandNumber(); } + + void markUndef() & { + op->set(SILUndef::get(getType(), *op->getUser()->getFunction())); + } + + SILInstruction *getInst() const { return op->getUser(); } + + /// Return true if this phi consumes a borrow. + /// + /// If so, we may need to insert an extra begin_borrow to balance the +1 when + /// converting owned ownership phis to guaranteed ownership phis. + bool isGuaranteedConsuming() const { + switch (getKind()) { + case Kind::Branch: + return true; + case Kind::Tuple: + case Kind::Struct: + return false; + } + } + + bool operator<(const OwnershipPhiOperand &other) const { + return op < other.op; + } + + bool operator==(const OwnershipPhiOperand &other) const { + return op == other.op; + } + + bool visitResults(function_ref visitor) const { + switch (getKind()) { + case Kind::Struct: + return visitor(cast(getInst())); + case Kind::Tuple: + return visitor(cast(getInst())); + case Kind::Branch: { + auto *br = cast(getInst()); + unsigned opNum = getOperandNumber(); + return llvm::all_of( + br->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) { + return visitor(succBlock->getSILPhiArguments()[opNum]); + }); + } + } + } +}; + +} // namespace semanticarc +} // namespace swift + +#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPPHIOPERAND_H diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index 180f3882a7807..383ec145a6455 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -11,6 +11,12 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-semantic-arc-opts" + +#include "swift/Basic/LLVM.h" + +#include "OwnershipPhiOperand.h" +#include "OwnershipLiveRange.h" + #include "swift/Basic/BlotSetVector.h" #include "swift/Basic/FrozenMultiMap.h" #include "swift/Basic/MultiMapCache.h" @@ -36,642 +42,7 @@ #include "llvm/Support/CommandLine.h" using namespace swift; - -STATISTIC(NumEliminatedInsts, "number of removed instructions"); -STATISTIC(NumLoadCopyConvertedToLoadBorrow, - "number of load_copy converted to load_borrow"); - -//===----------------------------------------------------------------------===// -// Ownership Phi Operand -//===----------------------------------------------------------------------===// - -namespace { - -/// The operand of a "phi" in the induced ownership graph of a def-use graph. -/// -/// Some examples: br, struct, tuple. -class OwnershipPhiOperand { -public: - enum Kind { - Branch, - Struct, - Tuple, - }; - -private: - Operand *op; - - OwnershipPhiOperand(Operand *op) : op(op) {} - -public: - static Optional get(const Operand *op) { - switch (op->getUser()->getKind()) { - case SILInstructionKind::BranchInst: - case SILInstructionKind::StructInst: - case SILInstructionKind::TupleInst: - return {{const_cast(op)}}; - default: - return None; - } - } - - Kind getKind() const { - switch (op->getUser()->getKind()) { - case SILInstructionKind::BranchInst: - return Kind::Branch; - case SILInstructionKind::StructInst: - return Kind::Struct; - case SILInstructionKind::TupleInst: - return Kind::Tuple; - default: - llvm_unreachable("unhandled case?!"); - } - } - - Operand *getOperand() const { return op; } - SILValue getValue() const { return op->get(); } - SILType getType() const { return op->get()->getType(); } - - unsigned getOperandNumber() const { return op->getOperandNumber(); } - - void markUndef() & { - op->set(SILUndef::get(getType(), *op->getUser()->getFunction())); - } - - SILInstruction *getInst() const { return op->getUser(); } - - /// Return true if this phi consumes a borrow. - /// - /// If so, we may need to insert an extra begin_borrow to balance the +1 when - /// converting owned ownership phis to guaranteed ownership phis. - bool isGuaranteedConsuming() const { - switch (getKind()) { - case Kind::Branch: - return true; - case Kind::Tuple: - case Kind::Struct: - return false; - } - } - - bool operator<(const OwnershipPhiOperand &other) const { - return op < other.op; - } - - bool operator==(const OwnershipPhiOperand &other) const { - return op == other.op; - } - - bool visitResults(function_ref visitor) const { - switch (getKind()) { - case Kind::Struct: - return visitor(cast(getInst())); - case Kind::Tuple: - return visitor(cast(getInst())); - case Kind::Branch: { - auto *br = cast(getInst()); - unsigned opNum = getOperandNumber(); - return llvm::all_of( - br->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) { - return visitor(succBlock->getSILPhiArguments()[opNum]); - }); - } - } - } -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Live Range Modeling -//===----------------------------------------------------------------------===// - -namespace { - -/// This class represents an "extended live range" of an owned value. Such a -/// representation includes: -/// -/// 1. The owned introducing value. -/// 2. Any forwarding instructions that consume the introduced value -/// (transitively) and then propagate a new owned value. -/// 3. Transitive destroys on the forwarding instructions/destroys on the owned -/// introducing value. -/// 4. Any unknown consuming uses that are not understood by this code. -/// -/// This allows for this to be used to convert such a set of uses from using -/// owned ownership to using guaranteed ownership by converting the -/// destroy_value -> end_borrow and "flipping" the ownership of individual -/// forwarding instructions. -/// -/// NOTE: We do not look through "phi nodes" in the ownership graph (e.x.: real -/// phi arguments, struct, tuple). Instead we represent those as nodes in a -/// larger phi ownership web, connected via individual OwnershipLiveRange. -class OwnershipLiveRange { - /// The value that we are computing the LiveRange for. Expected to be an owned - /// introducer and not to be forwarding. - OwnedValueIntroducer introducer; - - /// A vector that we store all of our uses into. - /// - /// Some properties of this array are: - /// - /// 1. It is only mutated in the constructor of LiveRange. - /// - /// 2. destroyingUses, ownershipForwardingUses, and unknownConsumingUses are - /// views into this array. We store the respective uses in the aforementioned - /// order. This is why it is important not to mutate consumingUses after we - /// construct the LiveRange since going from small -> large could invalidate - /// the uses. - SmallVector consumingUses; - - /// A list of destroy_values of the live range. - /// - /// This is just a view into consuming uses. - ArrayRef destroyingUses; - - /// A list of forwarding instructions that forward owned ownership, but that - /// are also able to be converted to guaranteed ownership. - /// - /// If we are able to eliminate this LiveRange due to it being from a - /// guaranteed value, we must flip the ownership of all of these instructions - /// to guaranteed from owned. - /// - /// NOTE: Normally only destroying or consuming uses end the live range. We - /// copy these transitive uses as well into the consumingUses array since - /// transitive uses can extend a live range up to an unreachable block without - /// ultimately being consuming. In such a situation if we did not also store - /// this into consuming uses, we would not be able to ascertain just using the - /// "consumingUses" array the true lifetime of the OwnershipLiveRange. - /// - /// Corresponds to isOwnershipForwardingInst(...). - ArrayRef ownershipForwardingUses; - - /// Consuming uses that we were not able to understand as a forwarding - /// instruction or a destroy_value. These must be passed a strongly control - /// equivalent +1 value. - ArrayRef unknownConsumingUses; - -public: - OwnershipLiveRange(SILValue value); - OwnershipLiveRange(const OwnershipLiveRange &) = delete; - OwnershipLiveRange &operator=(const OwnershipLiveRange &) = delete; - - enum class HasConsumingUse_t { - No = 0, - YesButAllPhiArgs = 1, - Yes = 2, - }; - - /// Return true if v only has invalidating uses that are destroy_value. Such - /// an owned value is said to represent a dead "live range". - /// - /// Semantically this implies that a value is never passed off as +1 to memory - /// or another function implying it can be used everywhere at +0. - HasConsumingUse_t - hasUnknownConsumingUse(bool assumingFixedPoint = false) const; - - /// Return an array ref to /all/ consuming uses. Will include all 3 sorts of - /// consuming uses: destroying uses, forwarding consuming uses, and unknown - /// forwarding instruction. - ArrayRef getAllConsumingUses() const { return consumingUses; } - - ArrayRef getDestroyingUses() const { return destroyingUses; } - -private: - struct OperandToUser; - -public: - using DestroyingInstsRange = - TransformRange, OperandToUser>; - DestroyingInstsRange getDestroyingInsts() const; - - using ConsumingInstsRange = - TransformRange, OperandToUser>; - ConsumingInstsRange getAllConsumingInsts() const; - - /// If this LiveRange has a single destroying use, return that use. Otherwise, - /// return nullptr. - Operand *getSingleDestroyingUse() const { - if (destroyingUses.size() != 1) { - return nullptr; - } - return destroyingUses.front(); - } - - /// If this LiveRange has a single unknown destroying use, return that - /// use. Otherwise, return nullptr. - Operand *getSingleUnknownConsumingUse() const { - if (unknownConsumingUses.size() != 1) { - return nullptr; - } - return unknownConsumingUses.front(); - } - - OwnedValueIntroducer getIntroducer() const { return introducer; } - - ArrayRef getOwnershipForwardingUses() const { - return ownershipForwardingUses; - } - - void convertOwnedGeneralForwardingUsesToGuaranteed() &&; - - /// A consuming operation that: - /// - /// 1. If \p insertEndBorrows is true inserts end borrows at all - /// destroying insts locations. - /// - /// 2. Deletes all destroy_values. - /// - /// 3. RAUW value with newGuaranteedValue. - /// - /// 4. Convert all of the general forwarding instructions from - /// @owned -> @guaranteed. "Like Dominoes". - /// - /// 5. Leaves all of the unknown consuming users alone. It is up to - /// the caller to handle converting their ownership. - void convertToGuaranteedAndRAUW(SILValue newGuaranteedValue, - InstModCallbacks callbacks) &&; - - /// A consuming operation that in order: - /// - /// 1. Converts the phi argument to be guaranteed via setOwnership. - /// - /// 2. If this consumes a borrow, insert end_borrows at the relevant - /// destroy_values. - /// - /// 3. Deletes all destroy_values. - /// - /// 4. Converts all of the general forwarding instructions from @owned -> - /// @guaranteed. "Like Dominoes". - /// - /// NOTE: This leaves all of the unknown consuming users alone. It is up to - /// the caller to handle converting their ownership. - /// - /// NOTE: This routine leaves inserting begin_borrows for the incoming values - /// to the caller since those are not part of the LiveRange itself. - void convertJoinedLiveRangePhiToGuaranteed( - DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, - InstModCallbacks callbacks) &&; - - /// Given a new guaranteed value, insert end_borrow for the newGuaranteedValue - /// at all of our destroy_values in prepration for converting from owned to - /// guaranteed. - /// - /// This is used when converting load [copy] -> load_borrow. - void insertEndBorrowsAtDestroys(SILValue newGuaranteedValue, - DeadEndBlocks &deadEndBlocks, - ValueLifetimeAnalysis::Frontier &scratch); -}; - -} // end anonymous namespace - -struct OwnershipLiveRange::OperandToUser { - OperandToUser() {} - - SILInstruction *operator()(const Operand *use) const { - auto *nonConstUse = const_cast(use); - return nonConstUse->getUser(); - } -}; - -OwnershipLiveRange::DestroyingInstsRange -OwnershipLiveRange::getDestroyingInsts() const { - return DestroyingInstsRange(getDestroyingUses(), OperandToUser()); -} - -OwnershipLiveRange::ConsumingInstsRange -OwnershipLiveRange::getAllConsumingInsts() const { - return ConsumingInstsRange(consumingUses, OperandToUser()); -} - -OwnershipLiveRange::OwnershipLiveRange(SILValue value) - : introducer(*OwnedValueIntroducer::get(value)), destroyingUses(), - ownershipForwardingUses(), unknownConsumingUses() { - assert(introducer.value.getOwnershipKind() == ValueOwnershipKind::Owned); - - SmallVector tmpDestroyingUses; - SmallVector tmpForwardingConsumingUses; - SmallVector tmpUnknownConsumingUses; - - // We know that our silvalue produces an @owned value. Look through all of our - // uses and classify them as either consuming or not. - SmallVector worklist(introducer.value->getUses()); - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - - // Skip type dependent operands. - if (op->isTypeDependent()) - continue; - - // Do a quick check that we did not add ValueOwnershipKind that are not - // owned to the worklist. - assert(op->get().getOwnershipKind() == ValueOwnershipKind::Owned && - "Added non-owned value to worklist?!"); - - auto *user = op->getUser(); - - // Ok, this constraint can take something owned as live. Assert that it - // can also accept something that is guaranteed. Any non-consuming use of - // an owned value should be able to take a guaranteed parameter as well - // (modulo bugs). We assert to catch these. - if (!op->isConsumingUse()) { - continue; - } - - // Ok, we know now that we have a consuming use. See if we have a destroy - // value, quickly up front. If we do have one, stash it and continue. - if (isa(user)) { - tmpDestroyingUses.push_back(op); - continue; - } - - // Otherwise, see if we have a forwarding value that has a single - // non-trivial operand that can accept a guaranteed value. If not, we can - // not recursively process it, so be conservative and assume that we /may - // consume/ the value, so the live range must not be eliminated. - // - // DISCUSSION: For now we do not support forwarding instructions with - // multiple non-trivial arguments since we would need to optimize all of - // the non-trivial arguments at the same time. - // - // NOTE: Today we do not support TermInsts for simplicity... we /could/ - // support it though if we need to. - auto *ti = dyn_cast(user); - if ((ti && !ti->isTransformationTerminator()) || - !isGuaranteedForwardingInst(user) || - 1 != count_if(user->getOperandValues( - true /*ignore type dependent operands*/), - [&](SILValue v) { - return v.getOwnershipKind() == - ValueOwnershipKind::Owned; - })) { - tmpUnknownConsumingUses.push_back(op); - continue; - } - - // Ok, this is a forwarding instruction whose ownership we can flip from - // owned -> guaranteed. - tmpForwardingConsumingUses.push_back(op); - - // If we have a non-terminator, just visit its users recursively to see if - // the the users force the live range to be alive. - if (!ti) { - for (SILValue v : user->getResults()) { - if (v.getOwnershipKind() != ValueOwnershipKind::Owned) - continue; - llvm::copy(v->getUses(), std::back_inserter(worklist)); - } - continue; - } - - // Otherwise, we know that we have no only a terminator, but a - // transformation terminator, so we should add the users of its results to - // the worklist. - for (auto &succ : ti->getSuccessors()) { - auto *succBlock = succ.getBB(); - - // If we do not have any arguments, then continue. - if (succBlock->args_empty()) - continue; - - for (auto *succArg : succBlock->getSILPhiArguments()) { - // If we have an any value, just continue. - if (succArg->getOwnershipKind() == ValueOwnershipKind::None) - continue; - - // Otherwise add all users of this BBArg to the worklist to visit - // recursively. - llvm::copy(succArg->getUses(), std::back_inserter(worklist)); - } - } - } - - // The order in which we append these to consumingUses matters since we assume - // their order as an invariant. This is done to ensure that we can pass off - // all of our uses or individual sub-arrays of our users without needing to - // move around memory. - llvm::copy(tmpDestroyingUses, std::back_inserter(consumingUses)); - llvm::copy(tmpForwardingConsumingUses, std::back_inserter(consumingUses)); - llvm::copy(tmpUnknownConsumingUses, std::back_inserter(consumingUses)); - - auto cUseArrayRef = llvm::makeArrayRef(consumingUses); - destroyingUses = cUseArrayRef.take_front(tmpDestroyingUses.size()); - ownershipForwardingUses = cUseArrayRef.slice( - tmpDestroyingUses.size(), tmpForwardingConsumingUses.size()); - unknownConsumingUses = cUseArrayRef.take_back(tmpUnknownConsumingUses.size()); -} - -void OwnershipLiveRange::insertEndBorrowsAtDestroys( - SILValue newGuaranteedValue, DeadEndBlocks &deadEndBlocks, - ValueLifetimeAnalysis::Frontier &scratch) { - assert(scratch.empty() && "Expected scratch to be initially empty?!"); - - // Since we are looking through forwarding uses that can accept guaranteed - // parameters, we can have multiple destroy_value along the same path. We need - // to find the post-dominating block set of these destroy value to ensure that - // we do not insert multiple end_borrow. - // - // TODO: Hoist this out? - SILInstruction *inst = introducer.value->getDefiningInstruction(); - Optional analysis; - if (!inst) { - analysis.emplace(cast(introducer.value), - getAllConsumingInsts()); - } else { - analysis.emplace(inst, getAllConsumingInsts()); - } - - // Use all consuming uses in our value lifetime analysis to ensure correctness - // in the face of unreachable code. - bool foundCriticalEdges = !analysis->computeFrontier( - scratch, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks); - (void)foundCriticalEdges; - assert(!foundCriticalEdges); - auto loc = RegularLocation::getAutoGeneratedLocation(); - while (!scratch.empty()) { - auto *insertPoint = scratch.pop_back_val(); - SILBuilderWithScope builder(insertPoint); - builder.createEndBorrow(loc, newGuaranteedValue); - } -} - -static void convertInstructionOwnership(SILInstruction *i, - ValueOwnershipKind oldOwnership, - ValueOwnershipKind newOwnership) { - // If this is a term inst, just convert all of its incoming values that are - // owned to be guaranteed. - if (auto *ti = dyn_cast(i)) { - for (auto &succ : ti->getSuccessors()) { - auto *succBlock = succ.getBB(); - - // If we do not have any arguments, then continue. - if (succBlock->args_empty()) - continue; - - for (auto *succArg : succBlock->getSILPhiArguments()) { - // If we have an any value, just continue. - if (succArg->getOwnershipKind() == oldOwnership) { - succArg->setOwnershipKind(newOwnership); - } - } - } - return; - } - - assert(i->hasResults()); - for (SILValue result : i->getResults()) { - if (auto *svi = dyn_cast(result)) { - if (svi->getOwnershipKind() == oldOwnership) { - svi->setOwnershipKind(newOwnership); - } - continue; - } - - if (auto *ofci = dyn_cast(result)) { - if (ofci->getOwnershipKind() == oldOwnership) { - ofci->setOwnershipKind(newOwnership); - } - continue; - } - - if (auto *sei = dyn_cast(result)) { - if (sei->getOwnershipKind() == oldOwnership) { - sei->setOwnershipKind(newOwnership); - } - continue; - } - - if (auto *mvir = dyn_cast(result)) { - if (mvir->getOwnershipKind() == oldOwnership) { - mvir->setOwnershipKind(newOwnership); - } - continue; - } - - llvm_unreachable("unhandled forwarding instruction?!"); - } -} - -void OwnershipLiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() && { - while (!ownershipForwardingUses.empty()) { - auto *i = ownershipForwardingUses.back()->getUser(); - ownershipForwardingUses = ownershipForwardingUses.drop_back(); - convertInstructionOwnership(i, ValueOwnershipKind::Owned, - ValueOwnershipKind::Guaranteed); - } -} - -void OwnershipLiveRange::convertToGuaranteedAndRAUW( - SILValue newGuaranteedValue, InstModCallbacks callbacks) && { - auto *value = cast(introducer.value); - while (!destroyingUses.empty()) { - auto *d = destroyingUses.back(); - destroyingUses = destroyingUses.drop_back(); - callbacks.deleteInst(d->getUser()); - ++NumEliminatedInsts; - } - - callbacks.eraseAndRAUWSingleValueInst(value, newGuaranteedValue); - - // Then change all of our guaranteed forwarding insts to have guaranteed - // ownership kind instead of what ever they previously had (ignoring trivial - // results); - std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); -} - -// TODO: If this is useful, move onto OwnedValueIntroducer itself? -static SILValue convertIntroducerToGuaranteed(OwnedValueIntroducer introducer) { - switch (introducer.kind) { - case OwnedValueIntroducerKind::Phi: { - auto *phiArg = cast(introducer.value); - phiArg->setOwnershipKind(ValueOwnershipKind::Guaranteed); - return phiArg; - } - case OwnedValueIntroducerKind::Struct: { - auto *si = cast(introducer.value); - si->setOwnershipKind(ValueOwnershipKind::Guaranteed); - return si; - } - case OwnedValueIntroducerKind::Tuple: { - auto *ti = cast(introducer.value); - ti->setOwnershipKind(ValueOwnershipKind::Guaranteed); - return ti; - } - case OwnedValueIntroducerKind::Copy: - case OwnedValueIntroducerKind::LoadCopy: - case OwnedValueIntroducerKind::Apply: - case OwnedValueIntroducerKind::BeginApply: - case OwnedValueIntroducerKind::TryApply: - case OwnedValueIntroducerKind::LoadTake: - case OwnedValueIntroducerKind::FunctionArgument: - case OwnedValueIntroducerKind::PartialApplyInit: - case OwnedValueIntroducerKind::AllocBoxInit: - case OwnedValueIntroducerKind::AllocRefInit: - return SILValue(); - } -} - -void OwnershipLiveRange::convertJoinedLiveRangePhiToGuaranteed( - DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch, - InstModCallbacks callbacks) && { - - // First convert the phi value itself to be guaranteed. - SILValue phiValue = convertIntroducerToGuaranteed(introducer); - - // Then insert end_borrows at each of our destroys if we are consuming. We - // have to convert the phi to guaranteed first since otherwise, the ownership - // check when we create the end_borrows will trigger. - if (introducer.hasConsumingGuaranteedOperands()) { - insertEndBorrowsAtDestroys(phiValue, deadEndBlocks, scratch); - } - - // Then eliminate all of the destroys... - while (!destroyingUses.empty()) { - auto *d = destroyingUses.back(); - destroyingUses = destroyingUses.drop_back(); - callbacks.deleteInst(d->getUser()); - ++NumEliminatedInsts; - } - - // and change all of our guaranteed forwarding insts to have guaranteed - // ownership kind instead of what ever they previously had (ignoring trivial - // results); - std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed(); -} - -OwnershipLiveRange::HasConsumingUse_t -OwnershipLiveRange::hasUnknownConsumingUse(bool assumingAtFixPoint) const { - // First do a quick check if we have /any/ unknown consuming - // uses. If we do not have any, return false early. - if (unknownConsumingUses.empty()) { - return HasConsumingUse_t::No; - } - - // Ok, we do have some unknown consuming uses. If we aren't assuming we are at - // the fixed point yet, just bail. - if (!assumingAtFixPoint) { - return HasConsumingUse_t::Yes; - } - - // We do not know how to handle yet cases where an owned value is used by - // multiple phi nodes. So we bail early if unknown consuming uses is > 1. - // - // TODO: Build up phi node web. - auto *op = getSingleUnknownConsumingUse(); - if (!op) { - return HasConsumingUse_t::Yes; - } - - // Make sure our single unknown consuming use is a branch inst. If not, bail, - // this is a /real/ unknown consuming use. - if (!OwnershipPhiOperand::get(op)) { - return HasConsumingUse_t::Yes; - } - - // Otherwise, setup the phi to incoming value map mapping the block arguments - // to our introducer. - return HasConsumingUse_t::YesButAllPhiArgs; -} +using namespace swift::semanticarc; //===----------------------------------------------------------------------===// // Address Written To Analysis @@ -1392,11 +763,9 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { while (!endBorrows.empty()) { auto *ebi = endBorrows.pop_back_val(); eraseInstruction(ebi); - ++NumEliminatedInsts; } eraseAndRAUWSingleValueInstruction(bbi, bbi->getOperand()); - ++NumEliminatedInsts; return true; } @@ -1612,7 +981,6 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization( // Otherwise, our copy must truly not be needed, o RAUW and convert to // guaranteed! std::move(lr).convertToGuaranteedAndRAUW(cvi->getOperand(), getCallbacks()); - ++NumEliminatedInsts; return true; } @@ -1627,7 +995,6 @@ bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue( if (auto *dvi = dyn_cast(op->getUser())) { eraseInstruction(dvi); eraseInstructionAndAddOperandsToWorklist(cvi); - NumEliminatedInsts += 2; return true; } } @@ -1651,10 +1018,8 @@ bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue( // Now that we have a truly dead live range copy value, eliminate it! while (!destroys.empty()) { eraseInstruction(destroys.pop_back_val()); - ++NumEliminatedInsts; } eraseInstructionAndAddOperandsToWorklist(cvi); - ++NumEliminatedInsts; return true; } @@ -1814,7 +1179,6 @@ bool SemanticARCOptVisitor::tryJoiningCopyValueLiveRangeWithOperand( if (canSafelyJoinSimpleRange(operand, dvi, cvi)) { eraseInstruction(dvi); eraseAndRAUWSingleValueInstruction(cvi, operand); - NumEliminatedInsts += 2; return true; } } @@ -2161,8 +1525,6 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) { lr.insertEndBorrowsAtDestroys(lbi, getDeadEndBlocks(), lifetimeFrontier); std::move(lr).convertToGuaranteedAndRAUW(lbi, getCallbacks()); - ++NumEliminatedInsts; - ++NumLoadCopyConvertedToLoadBorrow; return true; } From 76d0648e60e79153b2fe79699397f1788b3bb5eb Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Sat, 29 Aug 2020 21:46:58 -0700 Subject: [PATCH 448/663] [AutoDiff] [Sema] Include certain 'let' properties in 'Differentiable' derived conformances. (#33700) In `Differentiable` derived conformances, `let` properties are currently treated as if they had `@noDerivative` and excluded from the derived `Differentiable` conformance implementation. This is limiting to properties that have a non-mutating `move(along:)` (e.g. class properties), which can be mathematically treated as differentiable variables. This patch changes the derived conformances behavior such that `let` properties will be included as differentiable variables if they have a non-mutating `move(along:)`. This unblocks the following code: ```swift final class Foo: Differentiable { let x: ClassStuff // Class type with a non-mutating 'move(along:)' // Synthesized code: // struct TangentVector { // var x: ClassStuff.TangentVector // } // ... // func move(along direction: TangentVector) { // x.move(along: direction.x) // } } ``` Resolves SR-13474 (rdar://67982207). --- include/swift/AST/DiagnosticsSema.def | 7 ++- lib/Sema/DerivedConformanceDifferentiable.cpp | 56 ++++++++++++++----- .../class_differentiable.swift | 48 ++++++++++++++-- .../struct_differentiable.swift | 49 ++++++++++++++-- .../class_differentiation.swift | 15 +++++ 5 files changed, 147 insertions(+), 28 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 9374d59db3e3f..9d36c35bc7c80 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2823,15 +2823,16 @@ WARNING(differentiable_nondiff_type_implicit_noderivative_fixit,none, /*nominalCanDeriveAdditiveArithmetic*/ bool)) WARNING(differentiable_immutable_wrapper_implicit_noderivative_fixit,none, "synthesis of the 'Differentiable.move(along:)' requirement for %1 " - "requires 'wrappedValue' in property wrapper %0 to be mutable; " - "add an explicit '@noDerivative' attribute" + "requires 'wrappedValue' in property wrapper %0 to be mutable or have a " + "non-mutating 'move(along:)'; add an explicit '@noDerivative' attribute" "%select{|, or conform %1 to 'AdditiveArithmetic'}2", (/*wrapperType*/ Identifier, /*nominalName*/ Identifier, /*nominalCanDeriveAdditiveArithmetic*/ bool)) WARNING(differentiable_let_property_implicit_noderivative_fixit,none, "synthesis of the 'Differentiable.move(along:)' requirement for %0 " "requires all stored properties not marked with `@noDerivative` to be " - "mutable; use 'var' instead, or add an explicit '@noDerivative' attribute" + "mutable or have a non-mutating 'move(along:)'; use 'var' instead, or " + "add an explicit '@noDerivative' attribute " "%select{|, or conform %0 to 'AdditiveArithmetic'}1", (/*nominalName*/ Identifier, /*nominalCanDeriveAdditiveArithmetic*/ bool)) diff --git a/lib/Sema/DerivedConformanceDifferentiable.cpp b/lib/Sema/DerivedConformanceDifferentiable.cpp index 451dc2c65efad..5ab7ffc81c1ef 100644 --- a/lib/Sema/DerivedConformanceDifferentiable.cpp +++ b/lib/Sema/DerivedConformanceDifferentiable.cpp @@ -32,12 +32,37 @@ using namespace swift; +/// Return true if `move(along:)` can be invoked on the given `Differentiable`- +/// conforming property. +/// +/// If the given property is a `var`, return true because `move(along:)` can be +/// invoked regardless. Otherwise, return true if and only if the property's +/// type's 'Differentiable.move(along:)' witness is non-mutating. +static bool canInvokeMoveAlongOnProperty( + VarDecl *vd, ProtocolConformanceRef diffableConformance) { + assert(diffableConformance && "Property must conform to 'Differentiable'"); + // `var` always supports `move(along:)` since it is mutable. + if (vd->getIntroducer() == VarDecl::Introducer::Var) + return true; + // When the property is a `let`, the only case that would be supported is when + // it has a `move(along:)` protocol requirement witness that is non-mutating. + auto interfaceType = vd->getInterfaceType(); + auto &C = vd->getASTContext(); + auto witness = diffableConformance.getWitnessByName( + interfaceType, DeclName(C, C.Id_move, {C.Id_along})); + if (!witness) + return false; + auto *decl = cast(witness.getDecl()); + return decl->isNonMutating(); +} + /// Get the stored properties of a nominal type that are relevant for /// differentiation, except the ones tagged `@noDerivative`. static void -getStoredPropertiesForDifferentiation(NominalTypeDecl *nominal, DeclContext *DC, - SmallVectorImpl &result, - bool includeLetProperties = false) { +getStoredPropertiesForDifferentiation( + NominalTypeDecl *nominal, DeclContext *DC, + SmallVectorImpl &result, + bool includeLetPropertiesWithNonmutatingMoveAlong = false) { auto &C = nominal->getASTContext(); auto *diffableProto = C.getProtocol(KnownProtocolKind::Differentiable); for (auto *vd : nominal->getStoredProperties()) { @@ -53,15 +78,18 @@ getStoredPropertiesForDifferentiation(NominalTypeDecl *nominal, DeclContext *DC, // Skip stored properties with `@noDerivative` attribute. if (vd->getAttrs().hasAttribute()) continue; - // Skip `let` stored properties if requested. - // `mutating func move(along:)` cannot be synthesized to update `let` - // properties. - if (!includeLetProperties && vd->isLet()) - continue; if (vd->getInterfaceType()->hasError()) continue; auto varType = DC->mapTypeIntoContext(vd->getValueInterfaceType()); - if (!TypeChecker::conformsToProtocol(varType, diffableProto, nominal)) + auto conformance = TypeChecker::conformsToProtocol( + varType, diffableProto, nominal); + if (!conformance) + continue; + // Skip `let` stored properties with a mutating `move(along:)` if requested. + // `mutating func move(along:)` cannot be synthesized to update `let` + // properties. + if (!includeLetPropertiesWithNonmutatingMoveAlong && + !canInvokeMoveAlongOnProperty(vd, conformance)) continue; result.push_back(vd); } @@ -782,18 +810,18 @@ static void checkAndDiagnoseImplicitNoDerivative(ASTContext &Context, continue; // Check whether to diagnose stored property. auto varType = DC->mapTypeIntoContext(vd->getValueInterfaceType()); - bool conformsToDifferentiable = - !TypeChecker::conformsToProtocol(varType, diffableProto, nominal) - .isInvalid(); + auto diffableConformance = + TypeChecker::conformsToProtocol(varType, diffableProto, nominal); // If stored property should not be diagnosed, continue. - if (conformsToDifferentiable && !vd->isLet()) + if (diffableConformance && + canInvokeMoveAlongOnProperty(vd, diffableConformance)) continue; // Otherwise, add an implicit `@noDerivative` attribute. vd->getAttrs().add(new (Context) NoDerivativeAttr(/*Implicit*/ true)); auto loc = vd->getAttributeInsertionLoc(/*forModifier*/ false); assert(loc.isValid() && "Expected valid source location"); // Diagnose properties that do not conform to `Differentiable`. - if (!conformsToDifferentiable) { + if (!diffableConformance) { Context.Diags .diagnose( loc, diff --git a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift index f4b50fb19fa21..228c782375eba 100644 --- a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift +++ b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift @@ -29,26 +29,62 @@ func testEmpty() { assertConformsToAdditiveArithmetic(Empty.TangentVector.self) } +protocol DifferentiableWithNonmutatingMoveAlong: Differentiable {} +extension DifferentiableWithNonmutatingMoveAlong { + func move(along _: TangentVector) {} +} + +class EmptyWithInheritedNonmutatingMoveAlong: DifferentiableWithNonmutatingMoveAlong { + typealias TangentVector = Empty.TangentVector + var zeroTangentVectorInitializer: () -> TangentVector { { .init() } } + static func proof_that_i_have_nonmutating_move_along() { + let empty = EmptyWithInheritedNonmutatingMoveAlong() + empty.move(along: .init()) + } +} + +class EmptyWrapper: Differentiable {} +func testEmptyWrapper() { + assertConformsToAdditiveArithmetic(Empty.TangentVector.self) + assertConformsToAdditiveArithmetic(EmptyWrapper.TangentVector.self) +} + // Test structs with `let` stored properties. // Derived conformances fail because `mutating func move` requires all stored // properties to be mutable. -class ImmutableStoredProperties: Differentiable { +class ImmutableStoredProperties: Differentiable { var okay: Float // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let nondiff: Int - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let diff: Float - init() { + let letClass: Empty // No error on class-bound differentiable `let` with a non-mutating 'move(along:)'. + + let letClassWithInheritedNonmutatingMoveAlong: EmptyWithInheritedNonmutatingMoveAlong + + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + let letClassGeneric: T // Error due to lack of non-mutating 'move(along:)'. + + let letClassWrappingGeneric: EmptyWrapper // No error on class-bound differentiable `let` with a non-mutating 'move(along:)'. + + init(letClassGeneric: T) { okay = 0 nondiff = 0 diff = 0 + letClass = Empty() + self.letClassGeneric = letClassGeneric + self.letClassWrappingGeneric = EmptyWrapper() } } func testImmutableStoredProperties() { - _ = ImmutableStoredProperties.TangentVector(okay: 1) + _ = ImmutableStoredProperties.TangentVector( + okay: 1, + letClass: Empty.TangentVector(), + letClassWithInheritedNonmutatingMoveAlong: Empty.TangentVector(), + letClassWrappingGeneric: EmptyWrapper.TangentVector()) } class MutableStoredPropertiesWithInitialValue: Differentiable { var x = Float(1) @@ -56,7 +92,7 @@ class MutableStoredPropertiesWithInitialValue: Differentiable { } // Test class with both an empty constructor and memberwise initializer. class AllMixedStoredPropertiesHaveInitialValue: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let x = Float(1) var y = Float(1) // Memberwise initializer should be `init(y:)` since `x` is immutable. @@ -550,7 +586,7 @@ struct Generic {} extension Generic: Differentiable where T: Differentiable {} class WrappedProperties: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable; add an explicit '@noDerivative' attribute}} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable or have a non-mutating 'move(along:)'; add an explicit '@noDerivative' attribute}} @ImmutableWrapper var immutableInt: Generic = Generic() // expected-warning @+1 {{stored property 'mutableInt' has no derivative because 'Generic' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift index e75b2730232f5..d8ec6e56c588f 100644 --- a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift +++ b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift @@ -11,6 +11,35 @@ func testEmpty() { assertConformsToAdditiveArithmetic(Empty.TangentVector.self) } +struct EmptyWithConcreteNonmutatingMoveAlong: Differentiable { + typealias TangentVector = Empty.TangentVector + var zeroTangentVectorInitializer: () -> TangentVector { { .init() } } + func move(along _: TangentVector) {} + static func proof_that_i_have_nonmutating_move_along() { + let empty = Self() + empty.move(along: .init()) + } +} + +protocol DifferentiableWithNonmutatingMoveAlong: Differentiable {} +extension DifferentiableWithNonmutatingMoveAlong { + func move(along _: TangentVector) {} +} + +struct EmptyWithInheritedNonmutatingMoveAlong: DifferentiableWithNonmutatingMoveAlong { + typealias TangentVector = Empty.TangentVector + var zeroTangentVectorInitializer: () -> TangentVector { { .init() } } + static func proof_that_i_have_nonmutating_move_along() { + let empty = Self() + empty.move(along: .init()) + } +} + +class EmptyClass: Differentiable {} +func testEmptyClass() { + assertConformsToAdditiveArithmetic(EmptyClass.TangentVector.self) +} + // Test interaction with `AdditiveArithmetic` derived conformances. // Previously, this crashed due to duplicate memberwise initializer synthesis. struct EmptyAdditiveArithmetic: AdditiveArithmetic, Differentiable {} @@ -21,14 +50,24 @@ struct EmptyAdditiveArithmetic: AdditiveArithmetic, Differentiable {} struct ImmutableStoredProperties: Differentiable { var okay: Float - // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute, or conform 'ImmutableStoredProperties' to 'AdditiveArithmetic'}} {{3-3=@noDerivative }} + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let nondiff: Int - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute, or conform 'ImmutableStoredProperties' to 'AdditiveArithmetic}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let diff: Float + + let nonmutatingMoveAlongStruct: EmptyWithConcreteNonmutatingMoveAlong + + let inheritedNonmutatingMoveAlongStruct: EmptyWithInheritedNonmutatingMoveAlong + + let diffClass: EmptyClass // No error on class-bound `let` with a non-mutating `move(along:)`. } func testImmutableStoredProperties() { - _ = ImmutableStoredProperties.TangentVector(okay: 1) + _ = ImmutableStoredProperties.TangentVector( + okay: 1, + nonmutatingMoveAlongStruct: Empty.TangentVector(), + inheritedNonmutatingMoveAlongStruct: Empty.TangentVector(), + diffClass: EmptyClass.TangentVector()) } struct MutableStoredPropertiesWithInitialValue: Differentiable { var x = Float(1) @@ -36,7 +75,7 @@ struct MutableStoredPropertiesWithInitialValue: Differentiable { } // Test struct with both an empty constructor and memberwise initializer. struct AllMixedStoredPropertiesHaveInitialValue: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties not marked with `@noDerivative` to be mutable or have a non-mutating 'move(along:)'; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} let x = Float(1) var y = Float(1) // Memberwise initializer should be `init(y:)` since `x` is immutable. @@ -363,7 +402,7 @@ struct Generic {} extension Generic: Differentiable where T: Differentiable {} struct WrappedProperties: Differentiable { - // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable; add an explicit '@noDerivative' attribute}} + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'WrappedProperties' requires 'wrappedValue' in property wrapper 'ImmutableWrapper' to be mutable or have a non-mutating 'move(along:)'; add an explicit '@noDerivative' attribute}} @ImmutableWrapper var immutableInt: Generic // expected-warning @+1 {{stored property 'mutableInt' has no derivative because 'Generic' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} diff --git a/test/AutoDiff/validation-test/class_differentiation.swift b/test/AutoDiff/validation-test/class_differentiation.swift index 2ae7619486214..ee76c21ba1d87 100644 --- a/test/AutoDiff/validation-test/class_differentiation.swift +++ b/test/AutoDiff/validation-test/class_differentiation.swift @@ -524,4 +524,19 @@ ClassTests.test("ClassProperties") { gradient(at: Super(base: 2)) { foo in foo.squared }) } +ClassTests.test("LetProperties") { + final class Foo: Differentiable { + var x: Tracked + init(x: Tracked) { self.x = x } + } + final class Bar: Differentiable { + let x = Foo(x: 2) + } + let bar = Bar() + let grad = gradient(at: bar) { bar in (bar.x.x * bar.x.x).value } + expectEqual(Bar.TangentVector(x: .init(x: 6.0)), grad) + bar.move(along: grad) + expectEqual(8.0, bar.x.x) +} + runAllTests() From 76a81efac97550ea19968ab7ae4e1237da581f21 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 30 Aug 2020 01:25:54 -0400 Subject: [PATCH 449/663] ASTDemangler: Fix reconstruction of opaque result type defined in a constrained extension The mangling includes all generic parameters, even non-canonical ones. Fixes . --- lib/AST/ASTDemangler.cpp | 15 +++++---------- test/TypeDecoder/opaque_return_type.swift | 9 +++++++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index bf72c01eae702..d5fbfa63f56ae 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -200,21 +200,16 @@ createSubstitutionMapFromGenericArgs(GenericSignature genericSig, if (!genericSig) return SubstitutionMap(); - SmallVector genericParams; - genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) { - if (canonical) - genericParams.push_back(gp); - }); - if (genericParams.size() != args.size()) + if (genericSig->getGenericParams().size() != args.size()) return SubstitutionMap(); return SubstitutionMap::get( genericSig, [&](SubstitutableType *t) -> Type { - for (unsigned i = 0, e = genericParams.size(); i < e; ++i) { - if (t->isEqual(genericParams[i])) - return args[i]; - } + auto *gp = cast(t); + unsigned ordinal = genericSig->getGenericParamOrdinal(gp); + if (ordinal < args.size()) + return args[ordinal]; return Type(); }, LookUpConformanceInModule(moduleDecl)); diff --git a/test/TypeDecoder/opaque_return_type.swift b/test/TypeDecoder/opaque_return_type.swift index 94b139ad48d1e..327e4860570d8 100644 --- a/test/TypeDecoder/opaque_return_type.swift +++ b/test/TypeDecoder/opaque_return_type.swift @@ -12,6 +12,12 @@ var prop: some P { return 0 } func bar() -> some Sequence { return [] } +struct G {} + +extension G where T == Int { + var baz: some P { return 0 } +} + // DEMANGLE: $s18opaque_return_type3fooQryFQOyQo_ // CHECK: some P @@ -21,5 +27,8 @@ func bar() -> some Sequence { return [] } // DEMANGLE: $s18opaque_return_type3barQryFQOyQo_ // CHECK: some Sequence +// DEMANGLE: $s18opaque_return_type1GVAASiRszlE3bazQrvpQOySi_Qo_ +// CHECK: some P + // DEMANGLE: $s18opaque_return_type3barQryFQOyQo_7ElementSTQxD // CHECK: (some Sequence).Element From 96feb2dedda55fd54c8b1c724ae43e2002f62436 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 27 Aug 2020 23:54:33 -0700 Subject: [PATCH 450/663] [ownership] Extract out the main visitor SemanticARCOptVisitor from SemanticARCOpts.h into its own header. This is so I can move individual sub-optimizations on SemanticARCOptVisitor into their own files. So for instance, there will be one file containing the load [copy] optimization and another containing the phi optimization, etc. --- .../SemanticARC/SemanticARCOptVisitor.h | 252 ++++++++++++++++++ .../SemanticARC/SemanticARCOpts.cpp | 225 +--------------- 2 files changed, 257 insertions(+), 220 deletions(-) create mode 100644 lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h new file mode 100644 index 0000000000000..fce6908ae6252 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h @@ -0,0 +1,252 @@ +//===--- SemanticARCOptVisitor.h ------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H +#define SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H + +#include "swift/Basic/BlotSetVector.h" +#include "swift/Basic/FrozenMultiMap.h" +#include "swift/Basic/MultiMapCache.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/OwnershipUtils.h" +#include "swift/SIL/SILVisitor.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" + +namespace swift { +namespace semanticarc { + +bool constructCacheValue( + SILValue initialValue, + SmallVectorImpl &wellBehavedWriteAccumulator); + +/// A visitor that optimizes ownership instructions and eliminates any trivially +/// dead code that results after optimization. It uses an internal worklist that +/// is initialized on construction with targets to avoid iterator invalidation +/// issues. Rather than revisit the entire CFG like SILCombine and other +/// visitors do, we maintain a visitedSinceLastMutation list to ensure that we +/// revisit all interesting instructions in between mutations. +struct LLVM_LIBRARY_VISIBILITY SemanticARCOptVisitor + : SILInstructionVisitor { + /// Our main worklist. We use this after an initial run through. + SmallBlotSetVector worklist; + + /// A set of values that we have visited since the last mutation. We use this + /// to ensure that we do not visit values twice without mutating. + /// + /// This is specifically to ensure that we do not go into an infinite loop + /// when visiting phi nodes. + SmallBlotSetVector visitedSinceLastMutation; + + SILFunction &F; + Optional TheDeadEndBlocks; + ValueLifetimeAnalysis::Frontier lifetimeFrontier; + SmallMultiMapCache addressToExhaustiveWriteListCache; + + /// Are we assuming that we reached a fix point and are re-processing to + /// prepare to use the phiToIncomingValueMultiMap. + bool assumingAtFixedPoint = false; + + /// A map from a value that acts as a "joined owned introducer" in the def-use + /// graph. + /// + /// A "joined owned introducer" is a value with owned ownership whose + /// ownership is derived from multiple non-trivial owned operands of a related + /// instruction. Some examples are phi arguments, tuples, structs. Naturally, + /// all of these instructions must be non-unary instructions and only have + /// this property if they have multiple operands that are non-trivial. + /// + /// In such a case, we can not just treat them like normal forwarding concepts + /// since we can only eliminate optimize such a value if we are able to reason + /// about all of its operands together jointly. This is not amenable to a + /// small peephole analysis. + /// + /// Instead, as we perform the peephole analysis, using the multimap, we map + /// each joined owned value introducer to the set of its @owned operands that + /// we thought we could convert to guaranteed only if we could do the same to + /// the joined owned value introducer. Then once we finish performing + /// peepholes, we iterate through the map and see if any of our joined phi + /// ranges had all of their operand's marked with this property by iterating + /// over the multimap. Since we are dealing with owned values and we know that + /// our LiveRange can not see through joined live ranges, we know that we + /// should only be able to have a single owned value introducer for each + /// consumed operand. + FrozenMultiMap joinedOwnedIntroducerToConsumedOperands; + + /// If set to true, then we should only run cheap optimizations that do not + /// build up data structures or analyze code in depth. + /// + /// As an example, we do not do load [copy] optimizations here since they + /// generally involve more complex analysis, but simple peepholes of + /// copy_values we /do/ allow. + bool onlyGuaranteedOpts; + + using FrozenMultiMapRange = + decltype(joinedOwnedIntroducerToConsumedOperands)::PairToSecondEltRange; + + explicit SemanticARCOptVisitor(SILFunction &F, bool onlyGuaranteedOpts) + : F(F), addressToExhaustiveWriteListCache(constructCacheValue), + onlyGuaranteedOpts(onlyGuaranteedOpts) {} + + DeadEndBlocks &getDeadEndBlocks() { + if (!TheDeadEndBlocks) + TheDeadEndBlocks.emplace(&F); + return *TheDeadEndBlocks; + } + + /// Given a single value instruction, RAUW it with newValue, add newValue to + /// the worklist, and then call eraseInstruction on i. + void eraseAndRAUWSingleValueInstruction(SingleValueInstruction *i, + SILValue newValue) { + worklist.insert(newValue); + for (auto *use : i->getUses()) { + for (SILValue result : use->getUser()->getResults()) { + worklist.insert(result); + } + } + i->replaceAllUsesWith(newValue); + eraseInstructionAndAddOperandsToWorklist(i); + } + + /// Add all operands of i to the worklist and then call eraseInstruction on + /// i. Assumes that the instruction doesnt have users. + void eraseInstructionAndAddOperandsToWorklist(SILInstruction *i) { + // Then copy all operands into the worklist for future processing. + for (SILValue v : i->getOperandValues()) { + worklist.insert(v); + } + eraseInstruction(i); + } + + /// Pop values off of visitedSinceLastMutation, adding .some values to the + /// worklist. + void drainVisitedSinceLastMutationIntoWorklist() { + while (!visitedSinceLastMutation.empty()) { + Optional nextValue = visitedSinceLastMutation.pop_back_val(); + if (!nextValue.hasValue()) { + continue; + } + worklist.insert(*nextValue); + } + } + + /// Remove all results of the given instruction from the worklist and then + /// erase the instruction. Assumes that the instruction does not have any + /// users left. + void eraseInstruction(SILInstruction *i) { + // Remove all SILValues of the instruction from the worklist and then erase + // the instruction. + for (SILValue result : i->getResults()) { + worklist.erase(result); + visitedSinceLastMutation.erase(result); + } + i->eraseFromParent(); + + // Add everything else from visitedSinceLastMutation to the worklist. + drainVisitedSinceLastMutationIntoWorklist(); + } + + InstModCallbacks getCallbacks() { + return InstModCallbacks( + [this](SILInstruction *inst) { eraseInstruction(inst); }, + [](SILInstruction *) {}, [](SILValue, SILValue) {}, + [this](SingleValueInstruction *i, SILValue value) { + eraseAndRAUWSingleValueInstruction(i, value); + }); + } + + /// The default visitor. + bool visitSILInstruction(SILInstruction *i) { + assert(!isGuaranteedForwardingInst(i) && + "Should have forwarding visitor for all ownership forwarding " + "instructions"); + return false; + } + + bool visitCopyValueInst(CopyValueInst *cvi); + bool visitBeginBorrowInst(BeginBorrowInst *bbi); + bool visitLoadInst(LoadInst *li); + static bool shouldVisitInst(SILInstruction *i) { + switch (i->getKind()) { + default: + return false; + case SILInstructionKind::CopyValueInst: + case SILInstructionKind::BeginBorrowInst: + case SILInstructionKind::LoadInst: + return true; + } + } + +#define FORWARDING_INST(NAME) \ + bool visit##NAME##Inst(NAME##Inst *cls) { \ + for (SILValue v : cls->getResults()) { \ + worklist.insert(v); \ + } \ + return false; \ + } + FORWARDING_INST(Tuple) + FORWARDING_INST(Struct) + FORWARDING_INST(Enum) + FORWARDING_INST(OpenExistentialRef) + FORWARDING_INST(Upcast) + FORWARDING_INST(UncheckedRefCast) + FORWARDING_INST(ConvertFunction) + FORWARDING_INST(RefToBridgeObject) + FORWARDING_INST(BridgeObjectToRef) + FORWARDING_INST(UnconditionalCheckedCast) + FORWARDING_INST(UncheckedEnumData) + FORWARDING_INST(MarkUninitialized) + FORWARDING_INST(SelectEnum) + FORWARDING_INST(DestructureStruct) + FORWARDING_INST(DestructureTuple) + FORWARDING_INST(TupleExtract) + FORWARDING_INST(StructExtract) + FORWARDING_INST(OpenExistentialValue) + FORWARDING_INST(OpenExistentialBoxValue) + FORWARDING_INST(MarkDependence) + FORWARDING_INST(InitExistentialRef) + FORWARDING_INST(DifferentiableFunction) + FORWARDING_INST(LinearFunction) + FORWARDING_INST(DifferentiableFunctionExtract) + FORWARDING_INST(LinearFunctionExtract) +#undef FORWARDING_INST + +#define FORWARDING_TERM(NAME) \ + bool visit##NAME##Inst(NAME##Inst *cls) { \ + for (auto succValues : cls->getSuccessorBlockArgumentLists()) { \ + for (SILValue v : succValues) { \ + worklist.insert(v); \ + } \ + } \ + return false; \ + } + + FORWARDING_TERM(SwitchEnum) + FORWARDING_TERM(CheckedCastBranch) + FORWARDING_TERM(Branch) +#undef FORWARDING_TERM + + bool isWrittenTo(LoadInst *li, const OwnershipLiveRange &lr); + + bool processWorklist(); + bool optimize(); + + bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi); + bool eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi); + bool tryJoiningCopyValueLiveRangeWithOperand(CopyValueInst *cvi); + bool performPostPeepholeOwnedArgElimination(); +}; + +} // namespace semanticarc +} // namespace swift + +#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index 383ec145a6455..b501ed7e64cff 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -14,8 +14,9 @@ #include "swift/Basic/LLVM.h" -#include "OwnershipPhiOperand.h" #include "OwnershipLiveRange.h" +#include "OwnershipPhiOperand.h" +#include "SemanticARCOptVisitor.h" #include "swift/Basic/BlotSetVector.h" #include "swift/Basic/FrozenMultiMap.h" @@ -50,9 +51,9 @@ using namespace swift::semanticarc; /// Returns true if we were able to ascertain that either the initialValue has /// no write uses or all of the write uses were writes that we could understand. -static bool -constructCacheValue(SILValue initialValue, - SmallVectorImpl &wellBehavedWriteAccumulator) { +bool swift::semanticarc::constructCacheValue( + SILValue initialValue, + SmallVectorImpl &wellBehavedWriteAccumulator) { SmallVector worklist(initialValue->getUses()); while (!worklist.empty()) { @@ -186,222 +187,6 @@ constructCacheValue(SILValue initialValue, namespace { -/// A visitor that optimizes ownership instructions and eliminates any trivially -/// dead code that results after optimization. It uses an internal worklist that -/// is initialized on construction with targets to avoid iterator invalidation -/// issues. Rather than revisit the entire CFG like SILCombine and other -/// visitors do, we maintain a visitedSinceLastMutation list to ensure that we -/// revisit all interesting instructions in between mutations. -struct SemanticARCOptVisitor - : SILInstructionVisitor { - /// Our main worklist. We use this after an initial run through. - SmallBlotSetVector worklist; - - /// A set of values that we have visited since the last mutation. We use this - /// to ensure that we do not visit values twice without mutating. - /// - /// This is specifically to ensure that we do not go into an infinite loop - /// when visiting phi nodes. - SmallBlotSetVector visitedSinceLastMutation; - - SILFunction &F; - Optional TheDeadEndBlocks; - ValueLifetimeAnalysis::Frontier lifetimeFrontier; - SmallMultiMapCache addressToExhaustiveWriteListCache; - - /// Are we assuming that we reached a fix point and are re-processing to - /// prepare to use the phiToIncomingValueMultiMap. - bool assumingAtFixedPoint = false; - - /// A map from a value that acts as a "joined owned introducer" in the def-use - /// graph. - /// - /// A "joined owned introducer" is a value with owned ownership whose - /// ownership is derived from multiple non-trivial owned operands of a related - /// instruction. Some examples are phi arguments, tuples, structs. Naturally, - /// all of these instructions must be non-unary instructions and only have - /// this property if they have multiple operands that are non-trivial. - /// - /// In such a case, we can not just treat them like normal forwarding concepts - /// since we can only eliminate optimize such a value if we are able to reason - /// about all of its operands together jointly. This is not amenable to a - /// small peephole analysis. - /// - /// Instead, as we perform the peephole analysis, using the multimap, we map - /// each joined owned value introducer to the set of its @owned operands that - /// we thought we could convert to guaranteed only if we could do the same to - /// the joined owned value introducer. Then once we finish performing - /// peepholes, we iterate through the map and see if any of our joined phi - /// ranges had all of their operand's marked with this property by iterating - /// over the multimap. Since we are dealing with owned values and we know that - /// our LiveRange can not see through joined live ranges, we know that we - /// should only be able to have a single owned value introducer for each - /// consumed operand. - FrozenMultiMap joinedOwnedIntroducerToConsumedOperands; - - /// If set to true, then we should only run cheap optimizations that do not - /// build up data structures or analyze code in depth. - /// - /// As an example, we do not do load [copy] optimizations here since they - /// generally involve more complex analysis, but simple peepholes of - /// copy_values we /do/ allow. - bool onlyGuaranteedOpts; - - using FrozenMultiMapRange = - decltype(joinedOwnedIntroducerToConsumedOperands)::PairToSecondEltRange; - - explicit SemanticARCOptVisitor(SILFunction &F, bool onlyGuaranteedOpts) - : F(F), addressToExhaustiveWriteListCache(constructCacheValue), - onlyGuaranteedOpts(onlyGuaranteedOpts) {} - - DeadEndBlocks &getDeadEndBlocks() { - if (!TheDeadEndBlocks) - TheDeadEndBlocks.emplace(&F); - return *TheDeadEndBlocks; - } - - /// Given a single value instruction, RAUW it with newValue, add newValue to - /// the worklist, and then call eraseInstruction on i. - void eraseAndRAUWSingleValueInstruction(SingleValueInstruction *i, SILValue newValue) { - worklist.insert(newValue); - for (auto *use : i->getUses()) { - for (SILValue result : use->getUser()->getResults()) { - worklist.insert(result); - } - } - i->replaceAllUsesWith(newValue); - eraseInstructionAndAddOperandsToWorklist(i); - } - - /// Add all operands of i to the worklist and then call eraseInstruction on - /// i. Assumes that the instruction doesnt have users. - void eraseInstructionAndAddOperandsToWorklist(SILInstruction *i) { - // Then copy all operands into the worklist for future processing. - for (SILValue v : i->getOperandValues()) { - worklist.insert(v); - } - eraseInstruction(i); - } - - /// Pop values off of visitedSinceLastMutation, adding .some values to the - /// worklist. - void drainVisitedSinceLastMutationIntoWorklist() { - while (!visitedSinceLastMutation.empty()) { - Optional nextValue = visitedSinceLastMutation.pop_back_val(); - if (!nextValue.hasValue()) { - continue; - } - worklist.insert(*nextValue); - } - } - - /// Remove all results of the given instruction from the worklist and then - /// erase the instruction. Assumes that the instruction does not have any - /// users left. - void eraseInstruction(SILInstruction *i) { - // Remove all SILValues of the instruction from the worklist and then erase - // the instruction. - for (SILValue result : i->getResults()) { - worklist.erase(result); - visitedSinceLastMutation.erase(result); - } - i->eraseFromParent(); - - // Add everything else from visitedSinceLastMutation to the worklist. - drainVisitedSinceLastMutationIntoWorklist(); - } - - InstModCallbacks getCallbacks() { - return InstModCallbacks( - [this](SILInstruction *inst) { eraseInstruction(inst); }, - [](SILInstruction *) {}, [](SILValue, SILValue) {}, - [this](SingleValueInstruction *i, SILValue value) { - eraseAndRAUWSingleValueInstruction(i, value); - }); - } - - /// The default visitor. - bool visitSILInstruction(SILInstruction *i) { - assert(!isGuaranteedForwardingInst(i) && - "Should have forwarding visitor for all ownership forwarding " - "instructions"); - return false; - } - - bool visitCopyValueInst(CopyValueInst *cvi); - bool visitBeginBorrowInst(BeginBorrowInst *bbi); - bool visitLoadInst(LoadInst *li); - static bool shouldVisitInst(SILInstruction *i) { - switch (i->getKind()) { - default: - return false; - case SILInstructionKind::CopyValueInst: - case SILInstructionKind::BeginBorrowInst: - case SILInstructionKind::LoadInst: - return true; - } - } - -#define FORWARDING_INST(NAME) \ - bool visit##NAME##Inst(NAME##Inst *cls) { \ - for (SILValue v : cls->getResults()) { \ - worklist.insert(v); \ - } \ - return false; \ - } - FORWARDING_INST(Tuple) - FORWARDING_INST(Struct) - FORWARDING_INST(Enum) - FORWARDING_INST(OpenExistentialRef) - FORWARDING_INST(Upcast) - FORWARDING_INST(UncheckedRefCast) - FORWARDING_INST(ConvertFunction) - FORWARDING_INST(RefToBridgeObject) - FORWARDING_INST(BridgeObjectToRef) - FORWARDING_INST(UnconditionalCheckedCast) - FORWARDING_INST(UncheckedEnumData) - FORWARDING_INST(MarkUninitialized) - FORWARDING_INST(SelectEnum) - FORWARDING_INST(DestructureStruct) - FORWARDING_INST(DestructureTuple) - FORWARDING_INST(TupleExtract) - FORWARDING_INST(StructExtract) - FORWARDING_INST(OpenExistentialValue) - FORWARDING_INST(OpenExistentialBoxValue) - FORWARDING_INST(MarkDependence) - FORWARDING_INST(InitExistentialRef) - FORWARDING_INST(DifferentiableFunction) - FORWARDING_INST(LinearFunction) - FORWARDING_INST(DifferentiableFunctionExtract) - FORWARDING_INST(LinearFunctionExtract) -#undef FORWARDING_INST - -#define FORWARDING_TERM(NAME) \ - bool visit##NAME##Inst(NAME##Inst *cls) { \ - for (auto succValues : cls->getSuccessorBlockArgumentLists()) { \ - for (SILValue v : succValues) { \ - worklist.insert(v); \ - } \ - } \ - return false; \ - } - - FORWARDING_TERM(SwitchEnum) - FORWARDING_TERM(CheckedCastBranch) - FORWARDING_TERM(Branch) -#undef FORWARDING_TERM - - bool isWrittenTo(LoadInst *li, const OwnershipLiveRange &lr); - - bool processWorklist(); - bool optimize(); - - bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi); - bool eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi); - bool tryJoiningCopyValueLiveRangeWithOperand(CopyValueInst *cvi); - bool performPostPeepholeOwnedArgElimination(); -}; - } // end anonymous namespace static llvm::cl::opt From c9857397b19a3f9195728fabd1a2b054be101306 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sun, 30 Aug 2020 10:07:36 +0100 Subject: [PATCH 451/663] Use correct argument parser version in checkout --- utils/update_checkout/update-checkout-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 6eaf082df8efc..b3ddc61e64916 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -62,7 +62,7 @@ "llbuild": "master", "swift-tools-support-core": "master", "swiftpm": "swiftwasm", - "swift-argument-parser": "0.0.6", + "swift-argument-parser": "0.3.0", "swift-driver": "master", "swift-syntax": "master", "swift-stress-tester": "master", From 421bce3de7d400348db3540d207a0b2ca03a19d3 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Sun, 30 Aug 2020 03:06:14 -0700 Subject: [PATCH 452/663] Disable lldb tests in macOS nightly toolchain package (67923799) --- utils/build-presets.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 0892aee12e7c8..b1fe751b1ac4f 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1303,6 +1303,8 @@ mixin-preset= mixin_osx_package_test mixin_lightweight_assertions,no-stdlib-asserts +# SKIP LLDB TESTS (67923799) +skip-test-lldb [preset: buildbot_osx_package,no_assertions] mixin-preset= @@ -1313,8 +1315,6 @@ dash-dash no-assertions -# SKIP LLDB TESTS (67923799) -skip-test-lldb [preset: buildbot_osx_package,no_assertions,lto] mixin-preset=buildbot_osx_package,no_assertions From ba6d212af13619459b49a37e60e5d135453637c0 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sun, 30 Aug 2020 12:39:44 +0100 Subject: [PATCH 453/663] Move Foundation module files to correct path --- utils/webassembly/build-foundation.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/webassembly/build-foundation.sh b/utils/webassembly/build-foundation.sh index 88fcee67a2fa4..eeb18fcc9920d 100755 --- a/utils/webassembly/build-foundation.sh +++ b/utils/webassembly/build-foundation.sh @@ -30,4 +30,8 @@ ninja -v install if [[ "$(uname)" == "Darwin" ]]; then mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation -fi \ No newline at end of file +fi + +# .swiftdoc and .swiftmodule files should live in `swift`, not in `swift_static` +mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/wasi/wasm32/Foundation.swift* \ + $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32 \ No newline at end of file From 9d08f164cac9661ec60400c4b05ac6303398aab4 Mon Sep 17 00:00:00 2001 From: Valeriy Van Date: Mon, 24 Aug 2020 14:11:01 +0200 Subject: [PATCH 454/663] Fixes example snippet in Array.swift adding missing parameter label --- stdlib/public/core/Array.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index fd72700ca95b8..f7dfdcc9c2a11 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -852,14 +852,14 @@ extension Array: RangeReplaceableCollection { /// `LazyMapCollection, Int>` to a simple /// `[String]`. /// - /// func cacheImagesWithNames(names: [String]) { + /// func cacheImages(withNames names: [String]) { /// // custom image loading and caching /// } /// /// let namedHues: [String: Int] = ["Vermillion": 18, "Magenta": 302, /// "Gold": 50, "Cerise": 320] /// let colorNames = Array(namedHues.keys) - /// cacheImagesWithNames(colorNames) + /// cacheImages(withNames: colorNames) /// /// print(colorNames) /// // Prints "["Gold", "Cerise", "Magenta", "Vermillion"]" From f326927f458bfadf46eb2a780ff71029c49ed91f Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 28 Aug 2020 15:58:11 +0300 Subject: [PATCH 455/663] CSGen: Infer generic arguments in typed placeholders --- lib/Sema/CSGen.cpp | 5 +++-- test/Sema/editor_placeholders.swift | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 496052c162432..e4fab384e8efa 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3273,9 +3273,10 @@ namespace { Type visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) { if (auto *placeholderRepr = E->getPlaceholderTypeRepr()) { // Just resolve the referenced type. - // FIXME: The type reference needs to be opened into context. return resolveTypeReferenceInExpression( - placeholderRepr, TypeResolverContext::InExpression, nullptr); + placeholderRepr, TypeResolverContext::InExpression, + // Introduce type variables for unbound generics. + OpenUnboundGenericType(CS, CS.getConstraintLocator(E))); } auto locator = CS.getConstraintLocator(E); diff --git a/test/Sema/editor_placeholders.swift b/test/Sema/editor_placeholders.swift index dedeb59a440db..cf14d23b74fd2 100644 --- a/test/Sema/editor_placeholders.swift +++ b/test/Sema/editor_placeholders.swift @@ -2,6 +2,7 @@ func foo(_ x: Int) -> Int {} func foo(_ x: Float) -> Float {} +func foo(_ t: T) -> T {} var v = foo(<#T##x: Float##Float#>) // expected-error {{editor placeholder}} v = "" // expected-error {{cannot assign value of type 'String' to type 'Float'}} @@ -36,3 +37,6 @@ func test_ambiguity_with_placeholders(pairs: [(rank: Int, count: Int)]) -> Bool // expected-error@-1 {{editor placeholder in source file}} // expected-error@-2 {{ambiguous use of 'subscript(_:)'}} } + +let unboundInPlaceholder1: Array = <#T##Array#> // expected-error{{editor placeholder in source file}} +let unboundInPlaceholder2: Array = foo(<#T##t: Array##Array#>) // expected-error{{editor placeholder in source file}} From 9011e9d656cfb0a66cd41f2cceee5e3e55115bb1 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sun, 30 Aug 2020 19:54:26 +0100 Subject: [PATCH 456/663] Fix CoreFoundation headers on Linux --- utils/webassembly/build-foundation.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/webassembly/build-foundation.sh b/utils/webassembly/build-foundation.sh index eeb18fcc9920d..69a1e825f3887 100755 --- a/utils/webassembly/build-foundation.sh +++ b/utils/webassembly/build-foundation.sh @@ -30,6 +30,9 @@ ninja -v install if [[ "$(uname)" == "Darwin" ]]; then mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ $DESTINATION_TOOLCHAIN/usr/lib/swift/wasi/wasm32/CoreFoundation +else + mv $DESTINATION_TOOLCHAIN/usr/lib/swift_static/CoreFoundation \ + $DESTINATION_TOOLCHAIN/usr/lib/swift/CoreFoundation fi # .swiftdoc and .swiftmodule files should live in `swift`, not in `swift_static` From 6b1b8377f8ad01380f2398b0dd109a13cd67d1ba Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 28 Aug 2020 17:18:33 +0300 Subject: [PATCH 457/663] [NFC] CSGen: Tighten up resolveTypeReferenceInExpression Now that all sites have been refactored to pass a dedicated OpenUnboundGenericType callable, we can consistently move the construction of the opener into resolveTypeReferenceInExpression and have it take a ConstraintLocatorBuilder parameter instead --- lib/Sema/CSGen.cpp | 83 ++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 51 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index e4fab384e8efa..c3450ad9f39fd 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1328,17 +1328,11 @@ namespace { Type resolveTypeReferenceInExpression(TypeRepr *repr, TypeResolverContext resCtx, - OpenUnboundGenericTypeFn unboundTyOpener) { - if (!unboundTyOpener) { - unboundTyOpener = [](auto unboundTy) { - // FIXME: Don't let unbound generic types escape type resolution. - // For now, just return the unbound generic type. - return unboundTy; - }; - } - const auto result = - TypeResolution::forContextual(CS.DC, resCtx, unboundTyOpener) - .resolveType(repr); + const ConstraintLocatorBuilder &locator) { + // Introduce type variables for unbound generics. + const auto opener = OpenUnboundGenericType(CS, locator); + const auto result = TypeResolution::forContextual(CS.DC, resCtx, opener) + .resolveType(repr); if (result->hasError()) { return Type(); } @@ -1364,8 +1358,7 @@ namespace { auto *repr = E->getTypeRepr(); assert(repr && "Explicit node has no type repr!"); type = resolveTypeReferenceInExpression( - repr, TypeResolverContext::InExpression, - OpenUnboundGenericType(CS, locator)); + repr, TypeResolverContext::InExpression, locator); } if (!type || type->hasError()) return Type(); @@ -2067,10 +2060,8 @@ namespace { const auto resolvedTy = resolveTypeReferenceInExpression( closure->getExplicitResultTypeRepr(), TypeResolverContext::InExpression, - // Introduce type variables for unbound generics. - OpenUnboundGenericType( - CS, CS.getConstraintLocator( - closure, ConstraintLocator::ClosureResult))); + CS.getConstraintLocator(closure, + ConstraintLocator::ClosureResult)); if (resolvedTy) return resolvedTy; } @@ -2354,9 +2345,7 @@ namespace { const Type castType = resolveTypeReferenceInExpression( isPattern->getCastTypeRepr(), TypeResolverContext::InExpression, - OpenUnboundGenericType(CS, - locator.withPathElement( - LocatorPathElt::PatternMatch(pattern)))); + locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); if (!castType) return Type(); auto *subPattern = isPattern->getSubPattern(); @@ -2407,32 +2396,31 @@ namespace { FunctionRefKind functionRefKind = FunctionRefKind::Compound; if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) { // Resolve the parent type. - Type parentType = [&]() -> Type { - if (auto preTy = enumPattern->getParentType()) { - return preTy; + const auto parentType = [&] { + auto *const patternMatchLoc = CS.getConstraintLocator( + locator, {LocatorPathElt::PatternMatch(pattern), + ConstraintLocator::ParentType}); + + // FIXME: Sometimes the parent type is realized eagerly in + // ResolvePattern::visitUnresolvedDotExpr, so we have to open it + // ex post facto. Remove this once we learn how to resolve patterns + // while generating constraints to keep the opening of generic types + // contained within the type resolver. + if (const auto preresolvedTy = enumPattern->getParentType()) { + const auto openedTy = + CS.openUnboundGenericTypes(preresolvedTy, patternMatchLoc); + assert(openedTy); + return openedTy; } + return resolveTypeReferenceInExpression( enumPattern->getParentTypeRepr(), - TypeResolverContext::InExpression, [](auto unboundTy) { - // FIXME: We ought to pass an OpenUnboundGenericType object - // rather than calling CS.openUnboundGenericType below, but - // sometimes the parent type is resolved eagerly in - // ResolvePattern::visitUnresolvedDotExpr, letting unbound - // generics escape. - return unboundTy; - }); + TypeResolverContext::InExpression, patternMatchLoc); }(); if (!parentType) return Type(); - parentType = CS.openUnboundGenericTypes( - parentType, CS.getConstraintLocator( - locator, {LocatorPathElt::PatternMatch(pattern), - ConstraintLocator::ParentType})); - - assert(parentType); - // Perform member lookup into the parent's metatype. Type parentMetaType = MetatypeType::get(parentType); CS.addValueMemberConstraint( @@ -2976,8 +2964,7 @@ namespace { // Validate the resulting type. const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3003,8 +2990,7 @@ namespace { auto *const repr = expr->getCastTypeRepr(); const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3036,8 +3022,7 @@ namespace { auto *const repr = expr->getCastTypeRepr(); const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3064,8 +3049,7 @@ namespace { auto &ctx = CS.getASTContext(); const auto toType = resolveTypeReferenceInExpression( expr->getCastTypeRepr(), TypeResolverContext::ExplicitCastExpr, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(expr))); + CS.getConstraintLocator(expr)); if (!toType) return nullptr; @@ -3275,8 +3259,7 @@ namespace { // Just resolve the referenced type. return resolveTypeReferenceInExpression( placeholderRepr, TypeResolverContext::InExpression, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, CS.getConstraintLocator(E))); + CS.getConstraintLocator(E)); } auto locator = CS.getConstraintLocator(E); @@ -3347,9 +3330,7 @@ namespace { // If a root type was explicitly given, then resolve it now. if (auto rootRepr = E->getRootType()) { const auto rootObjectTy = resolveTypeReferenceInExpression( - rootRepr, TypeResolverContext::InExpression, - // Introduce type variables for unbound generics. - OpenUnboundGenericType(CS, locator)); + rootRepr, TypeResolverContext::InExpression, locator); if (!rootObjectTy || rootObjectTy->hasError()) return Type(); From 88e26c019fbdb8b4f212dc4c001d60683a3e6b1d Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sun, 30 Aug 2020 21:21:51 -0300 Subject: [PATCH 458/663] [NFC] Correcting minor typo on a CSDiagnostics comment --- lib/Sema/CSDiagnostics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index ed980fef21cb6..2ccc3a88d63d5 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -643,7 +643,7 @@ Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( void GenericArgumentsMismatchFailure::emitNoteForMismatch(int position) { auto *locator = getLocator(); - // Since there could be implicit conversions assoicated with argument + // Since there could be implicit conversions associated with argument // to parameter conversions, let's use parameter type as a source of // generic parameter information. auto paramSourceTy = From f8e14bab9eceec9f9cf8aa69579697b997fe4063 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 31 Aug 2020 11:51:09 +0100 Subject: [PATCH 459/663] Define SWIFT_STDLIB_SINGLE_THREADED_RUNTIME --- utils/build-presets.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 29b6fbf70d46e..9c186459f8873 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -2604,6 +2604,7 @@ extra-cmake-options= -DSWIFT_PRIMARY_VARIANT_SDK:STRING=WASI -DSWIFT_PRIMARY_VARIANT_ARCH:STRING=wasm32 -DSWIFT_SDKS='WASI;LINUX' + -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME=TRUE -DSWIFT_BUILD_SOURCEKIT=FALSE -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE @@ -2620,6 +2621,7 @@ extra-cmake-options= -DSWIFT_PRIMARY_VARIANT_SDK:STRING=WASI -DSWIFT_PRIMARY_VARIANT_ARCH:STRING=wasm32 -DSWIFT_SDKS='WASI' + -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME=TRUE -DSWIFT_OSX_x86_64_ICU_STATICLIB=TRUE -DSWIFT_BUILD_SOURCEKIT=FALSE -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE From ec3c27cdcb1ac2de775030ebf562af63900275e8 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 31 Aug 2020 12:03:53 +0100 Subject: [PATCH 460/663] Cleanup `Once.cpp` for single-threaded runtime --- stdlib/public/runtime/Once.cpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index 84403f7825586..d77e9c002dfd2 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -61,28 +61,7 @@ void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), dispatch_once_f(predicate, context, fn); #elif defined(__CYGWIN__) _swift_once_f(predicate, context, fn); -#elif defined(__wasm__) - // WebAssembly: hack: Swift compiler passes in a fn that doesn't take a parameter, - // which is invalid in WebAssembly. So swift_once casts the function. - // The correct way to fix this is to change - // SILGenModule::emitLazyGlobalInitializer - // but this is OK as a proof of concept. - // Keep a copy of the unmodified swift_once function below. - std::call_once(*predicate, [fn, context]() { ((void (*)())fn)(); }); #else std::call_once(*predicate, [fn, context]() { fn(context); }); #endif -} - -#ifdef __wasm__ -void swift::swift_once_real(swift_once_t *predicate, void (*fn)(void *), - void *context) { -#if defined(__APPLE__) - dispatch_once_f(predicate, context, fn); -#elif defined(__CYGWIN__) - _swift_once_f(predicate, context, fn); -#else - std::call_once(*predicate, [fn, context]() { fn(context); }); -#endif -} -#endif +} \ No newline at end of file From 294bde951b2b735a45ccd311d867d094db05c318 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Mon, 31 Aug 2020 08:46:24 -0400 Subject: [PATCH 461/663] Documentation fix: remainder matches sign of lhs, not rhs. --- stdlib/public/core/Integers.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/Integers.swift b/stdlib/public/core/Integers.swift index 7c637c6fe7bc9..1b7ba775989ff 100644 --- a/stdlib/public/core/Integers.swift +++ b/stdlib/public/core/Integers.swift @@ -1211,7 +1211,7 @@ public protocol BinaryInteger : /// /// - Parameter rhs: The value to divide this value by. /// - Returns: A tuple containing the quotient and remainder of this value - /// divided by `rhs`. The remainder has the same sign as `rhs`. + /// divided by `rhs`. The remainder has the same sign as `lhs`. func quotientAndRemainder(dividingBy rhs: Self) -> (quotient: Self, remainder: Self) From 2c8b845387d1393518311681d5ae865c0b7f358d Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Thu, 27 Aug 2020 10:54:21 -0700 Subject: [PATCH 462/663] IRGen: Ignore the metadata of fixed sized types with opaque result type parameters The removed check by this patch seems somewhat arbitrary and the test case that was added for it no longer fails. rdar://67841860 --- lib/IRGen/Outlining.cpp | 5 +-- ...que_result_type_private_underlying_2.swift | 36 +++++++++++++++++++ ...paque_result_type_private_underlying.swift | 8 +++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/IRGen/Outlining.cpp b/lib/IRGen/Outlining.cpp index 68f2d171732b2..fe39a1c9d52ec 100644 --- a/lib/IRGen/Outlining.cpp +++ b/lib/IRGen/Outlining.cpp @@ -39,7 +39,6 @@ void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType type) { } // Substitute opaque types if allowed. - auto origType = type; type = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(type, CanGenericSignature()); @@ -49,9 +48,7 @@ void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType type) { // We don't need the metadata for fixed size types or types that are not ABI // accessible. Outlining will call the value witness of the enclosing type of // non ABI accessible field/element types. - if ((!origType.getASTType()->hasOpaqueArchetype() && - isa(ti)) || - !ti.isABIAccessible()) { + if (isa(ti) || !ti.isABIAccessible()) { return; } diff --git a/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift b/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift index 2699a3405908a..ebabbef714c62 100644 --- a/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift +++ b/test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift @@ -45,3 +45,39 @@ public struct PublicUnderlyingInlinable : A { return PublicS() } } + + +public protocol P {} + +private struct PrivateSome : P {} +public func getSome() -> some P { + return PrivateSome() +} + +@propertyWrapper +public struct Wrapper { + public var wrappedValue: T + + public init(wrappedValue v: T) { + wrappedValue = v + } +} + +public struct R: P { + @Wrapper private var privateState = PrivateState() + var x: T? = nil + + public init(_ v: V.Type, _ t: T) { + x = t + } + + public mutating func modify() { + x = nil + } +} + +private extension R { + struct PrivateState { + var x = 0 + } +} diff --git a/test/IRGen/opaque_result_type_private_underlying.swift b/test/IRGen/opaque_result_type_private_underlying.swift index 85c975c77a2e0..a1b6f726704b3 100644 --- a/test/IRGen/opaque_result_type_private_underlying.swift +++ b/test/IRGen/opaque_result_type_private_underlying.swift @@ -68,3 +68,11 @@ public struct MyThing { } } #endif + +public struct E { + var body : some P { + var r = R(V.self, getSome()) + r.modify() + return r + } +} From 04b2d00b9ac2b94240c9bc098afb9767b23b3675 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 31 Aug 2020 16:54:12 +0200 Subject: [PATCH 463/663] CSE: disable CSE of lazy property getters of struct We cannot prove that the whole struct is overwritten between two lazy property getters. We would need AliasAnalysis for this, but currently this is not used in CSE. rdar://problem/67734844 --- lib/SILOptimizer/Transforms/CSE.cpp | 8 +++ test/SILOptimizer/cse.sil | 50 +++++++++++++++++++ test/SILOptimizer/lazy_property_getters.swift | 37 ++++++++++++-- 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp index f62fa49cb3719..1e1f6bbd74827 100644 --- a/lib/SILOptimizer/Transforms/CSE.cpp +++ b/lib/SILOptimizer/Transforms/CSE.cpp @@ -831,6 +831,14 @@ static bool isLazyPropertyGetter(ApplyInst *ai) { !callee->isLazyPropertyGetter()) return false; + // Only handle classes, but not structs. + // Lazy property getters of structs have an indirect inout self parameter. + // We don't know if the whole struct is overwritten between two getter calls. + // In such a case, the lazy property could be reset to an Optional.none. + // TODO: We could check this case with AliasAnalysis. + if (ai->getArgument(0)->getType().isAddress()) + return false; + // Check if the first block has a switch_enum of an Optional. // We don't handle getters of generic types, which have a switch_enum_addr. // This will be obsolete with opaque values anyway. diff --git a/test/SILOptimizer/cse.sil b/test/SILOptimizer/cse.sil index 60df4ccb7d4a6..dc56c783ec8e2 100644 --- a/test/SILOptimizer/cse.sil +++ b/test/SILOptimizer/cse.sil @@ -1306,3 +1306,53 @@ bb0(%0 : $@thick SpecialEnum.Type): %4 = struct $Bool (%3 : $Builtin.Int1) return %4 : $Bool } + +struct StructWithLazyProperty { + var lazyProperty: Int64 { mutating get set } + @_hasStorage @_hasInitialValue var lazyPropertyStorage : Int64? { get set } +} + +sil private [lazy_getter] [noinline] @lazy_getter : $@convention(method) (@inout StructWithLazyProperty) -> Int64 { +bb0(%0 : $*StructWithLazyProperty): + %2 = struct_element_addr %0 : $*StructWithLazyProperty, #StructWithLazyProperty.lazyPropertyStorage + %3 = load %2 : $*Optional + switch_enum %3 : $Optional, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2 + +bb1(%5 : $Int64): + br bb3(%5 : $Int64) + +bb2: + %9 = integer_literal $Builtin.Int64, 27 + %10 = struct $Int64 (%9 : $Builtin.Int64) + %12 = enum $Optional, #Optional.some!enumelt, %10 : $Int64 + store %12 to %2 : $*Optional + br bb3(%10 : $Int64) + +bb3(%15 : $Int64): + return %15 : $Int64 +} + +sil @take_int : $@convention(thin) (Int64) -> () + +// CHECK-LABEL: sil @dont_cse_lazy_property_of_overwritten_struct : $@convention(thin) () -> () { +// CHECK: [[GETTER:%[0-9]+]] = function_ref @lazy_getter +// CHECK: apply [[GETTER]] +// CHECK: apply [[GETTER]] +// CHECK: } // end sil function 'dont_cse_lazy_property_of_overwritten_struct' +sil @dont_cse_lazy_property_of_overwritten_struct : $@convention(thin) () -> () { +bb0: + %0 = alloc_stack $StructWithLazyProperty + %4 = enum $Optional, #Optional.none!enumelt + %5 = struct $StructWithLazyProperty (%4 : $Optional) + store %5 to %0 : $*StructWithLazyProperty + %7 = function_ref @lazy_getter : $@convention(method) (@inout StructWithLazyProperty) -> Int64 + %8 = apply %7(%0) : $@convention(method) (@inout StructWithLazyProperty) -> Int64 + %9 = function_ref @take_int : $@convention(thin) (Int64) -> () + %10 = apply %9(%8) : $@convention(thin) (Int64) -> () + store %5 to %0 : $*StructWithLazyProperty + %18 = apply %7(%0) : $@convention(method) (@inout StructWithLazyProperty) -> Int64 + %20 = apply %9(%18) : $@convention(thin) (Int64) -> () + dealloc_stack %0 : $*StructWithLazyProperty + %22 = tuple () + return %22 : $() +} diff --git a/test/SILOptimizer/lazy_property_getters.swift b/test/SILOptimizer/lazy_property_getters.swift index e3e8b9d1eb7b1..2880d06cd8758 100644 --- a/test/SILOptimizer/lazy_property_getters.swift +++ b/test/SILOptimizer/lazy_property_getters.swift @@ -88,20 +88,42 @@ func test_no_hoisting(_ c: Myclass, _ b: Bool) -> Int { return v } +// This test is disabled, because for structs, it does not work yet. +// CSE is too conservative to handle indirect getter arguments currently. + // CHECK-LABEL: sil {{.*}} @$s4test0A7_structySiAA8MystructVF +// CHECK-DISABLED: [[GETTER:%[0-9]+]] = function_ref @$s4test8MystructV4lvarSivg +// CHECK-DISABLED: [[V1:%[0-9]+]] = apply [[GETTER]]({{.*}}) +// CHECK-DISABLED: [[V2OPT:%[0-9]+]] = load +// CHECK-DISABLED: [[V2:%[0-9]+]] = unchecked_enum_data [[V2OPT]] +// CHECK-DISABLED: [[V1VAL:%[0-9]+]] = struct_extract [[V1]] +// CHECK-DISABLED: [[V2VAL:%[0-9]+]] = struct_extract [[V2]] +// CHECK-DISABLED: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2VAL]] +// CHECK-DISABLED: } // end sil function '$s4test0A7_structySiAA8MystructVF' +@inline(never) +func test_struct(_ s: Mystruct) -> Int { + var sm = s + g = 42 + let v1 = sm.lvar + let v2 = sm.lvar + return v1 &+ v2 +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A19_overwritten_structySiAA8MystructVF // CHECK: [[GETTER:%[0-9]+]] = function_ref @$s4test8MystructV4lvarSivg // CHECK: [[V1:%[0-9]+]] = apply [[GETTER]]({{.*}}) -// CHECK: [[V2OPT:%[0-9]+]] = load -// CHECK: [[V2:%[0-9]+]] = unchecked_enum_data [[V2OPT]] +// CHECK: [[V2:%[0-9]+]] = apply [[GETTER]]({{.*}}) // CHECK: [[V1VAL:%[0-9]+]] = struct_extract [[V1]] // CHECK: [[V2VAL:%[0-9]+]] = struct_extract [[V2]] // CHECK: builtin "sadd{{.*}}"([[V1VAL]] {{.*}}, [[V2VAL]] -// CHECK: } // end sil function '$s4test0A7_structySiAA8MystructVF' +// CHECK: } // end sil function '$s4test0A19_overwritten_structySiAA8MystructVF' @inline(never) -func test_struct(_ s: Mystruct) -> Int { +func test_overwritten_struct(_ s: Mystruct) -> Int { var sm = s g = 42 let v1 = sm.lvar + sm = s + g = 43 let v2 = sm.lvar return v1 &+ v2 } @@ -133,6 +155,13 @@ func calltests() { // CHECK-OUTPUT-NEXT: lvar init // CHECK-OUTPUT-NEXT: 84 print(test_struct(Mystruct())) + + // CHECK-OUTPUT-LABEL: test_overwritten_struct + print("test_overwritten_struct") + // CHECK-OUTPUT-NEXT: lvar init + // CHECK-OUTPUT-NEXT: lvar init + // CHECK-OUTPUT-NEXT: 85 + print(test_overwritten_struct(Mystruct())) } calltests() From 310c2656f0a05e52c2cdb0bc3f42460b8fb07c0b Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Mon, 31 Aug 2020 09:59:55 -0700 Subject: [PATCH 464/663] Reorganize DynamicCasting spec This only rearranges the existing sections; it does not change any technical points. This attempts to make the spec a little clearer by grouping the individual type discussions under four main headings: * Classes and Foreign Types. This includes Swift classes, Obj-C classes, and CF types. * Other Concrete Types. Struct, Enum, Tuple, Function, Optional, and Set/Dict/Array * Existential Types. Any, AnyObject, Error, Protocol types, and AnyHashable(*) * Metatypes & Existential Metatypes (*) This organization seems to flow a little better. In particular, it gives me a place to discuss issues common to all Existential types, which I'll work through in a subsequent PR. Footnotes: This organization isn't perfect, of course: * AnyHashable isn't really an Existential type, but it behaves as such for casting purposes, so it makes the most sense to discuss it in the Existentials section. * Metatypes are technically concrete types, but it seems to make more sense to discuss them after discussing Existential types. --- docs/DynamicCasting.md | 351 ++++++++++++++++++++++------------------- 1 file changed, 189 insertions(+), 162 deletions(-) diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md index 72b369bbb3c7c..95568d12119bd 100644 --- a/docs/DynamicCasting.md +++ b/docs/DynamicCasting.md @@ -43,7 +43,12 @@ a as? Int // Succeeds a as! Int == a // true ``` -## Classes +## Class and Foreign Types + +Class types generally follow standard object-oriented casting conventions. +Objective-C and CoreFoundation (CF) types follow the behaviors expected from Objective-C. + +### Classes Casting among class types follows standard object-oriented programming conventions: @@ -62,31 +67,80 @@ Invariants: * For any class type `C`: `c is C` iff `(c as! AnyObject) is C` * For any class type `C`: if `c is C`, then `(c as! AnyObject) as! C === c` -## Structs and Enums +### CoreFoundation types -You cannot cast between different concrete struct or enum types. -More formally: +* If `CF` is a CoreFoundation type, `cf` is an instance of `CF`, and `NS` is the corresponding Objective-C type, then `cf is NS == true` +* Further, since every Objective-C type inherits from `NSObject`, `cf is NSObject == true` +* In the above situation, if `T` is some other type and `cf is NS == true`, then `cf as! NS is T` iff `cf is T`. -* If `S` and `T` are struct or enum types and `s is S == true`, then `s is T` iff `S.self == T.self`. +The intention of the above is to treat instances of CoreFoundation types as being simultaneously instances of the corresponding Objective-C type, in keeping with the general dual nature of these types. +In particular, if a protocol conformance is declared on the Objective-C type, then instances of the CoreFoundation type can be cast to the protocol type directly. -## Tuples +XXX TODO: Converse? If ObjC instance has CF equivalent and CF type is extended, ... ?? -Casting from a tuple type T1 to a tuple type T2 will succeed iff the following hold: -* T1 and T2 have the same number of elements -* If an element has a label in both T1 and T2, the labels are identical -* Each element of T1 can be individually cast to the corresponding type of T2 +### Objective-C types -## Functions +The following discussion applies in three different cases: +* _Explicit_ conversions from use of the `is`, `as?`, and `as!` operators. +* _Implicit_ conversions from Swift to Objective-C: These conversions are generated automatically when Swift code calls an Objective-C function or method with an argument that is not already of an Objective-C type, or when a Swift function returns a value to an Objective-C caller. +* _Implicit_ conversions from Objective-C to Swift: These are generated automatically when arguments are passed from an Objective-C caller to a Swift function, or when an Objective-C function returns a value to a Swift caller. +Unless stated otherwise, all of the following cases apply equally to all three of the above cases. -Casting from a function type F1 to a function type F2 will succeed iff the following hold: -* The two types have the same number of arguments -* Corresponding arguments have identical types -* The return types are identical -* If F1 is a throwing function type, then F2 must be a throwing function type. If F1 is not throwing, then F2 may be a throwing or non-throwing function type. +Explicit casts among Swift and Objective-C class types follow the same general rules described earlier for class types in general. +Likewise, explicitly casting a class instance to an Objective-C protocol type follows the general rules for casts to protocol types. -Note that it is _not_ sufficient for argument and return types to be castable; they must actually be identical. +XXX TODO EXPLAIN Implicit conversions from Objective-C types to Swift types XXXX. + +CoreFoundation types can be explicitly cast to and from their corresponding Objective-C types as described above. + +Objective-C types and protocols +* `T` is an Objective-C class type iff `T.self is NSObject.Type` +* `P` is an Objective-C protocol iff XXX TODO XXX + +### The `_ObjectiveCBridgeable` Protocol + +The `_ObjectiveCBridgeable` protocol allows certain types to opt into custom casting behavior. +Note that although this mechanism was explicitly designed to simplify Swift interoperability with Objective-C, it is not necessarily tied to Objective-C. + +The `_ObjectiveCBridgeable` protocol defines an associated reference type `_ObjectiveCType`, along with a collection of methods that support casting to and from the associated `_ObjectiveCType`. +This protocol allows library code to provide tailored mechanisms for casting Swift types to reference types. +When casting to `AnyObject`, the casting logic prefers this tailored mechanism to the general `_SwiftValue` container mentioned above. -## Optionals +Note: The associated `_ObjectiveCType` is constrained to be a subtype of `AnyObject`; it is not limited to being an actual Objective-C type. +In particular, this mechanism is equally available to the Swift implementation of Foundation on non-Apple platforms and the Objective-C Foundation on Apple platforms. + +Example #1: Foundation extends the `Array` type in the standard library with an `_ObjectiveCBridgeable` conformance to `NSArray`. This allows Swift arrays to be cast to and from Foundation `NSArray` instances. +``` +let a = [1, 2, 3] // Array +let b = a as? AnyObject // casts to NSArray +``` + +Example #2: Foundation also extends each Swift numeric type with an `_ObjectiveCBridgeable` conformance to `NSNumber`. +``` +let a = 1 // Int +// After the next line, b is an Optional +// holding a reference to an NSNumber +let b = a as? AnyObject +// NSNumber is bridgeable to Double +let c = b as? Double +``` + +## Other Concrete Types + +In addition to the class types described earlier, Swift has several other kinds of concrete types. + +Casting between the different kinds described below (such as casting an enum to a tuple) will always fail. + +### Structs and Enums + +You cannot cast between different concrete struct or enum types. +More formally: + +* If `S` and `T` are struct or enum types and `s is S == true`, then `s is T` iff `S.self == T.self`. + +Struct or enum types can be cast to class types if the struct or enum implements the `_ObjectiveCBridgeable` protocol as described earlier. + +### Optionals Casting to and from optional types will transparently unwrap optionals as much as necessary, including nested optional types. @@ -156,7 +210,105 @@ t1 as? U? // Produces .some(.none) t4 as? U?? // Produces .some(.none) ``` -## Any +### Array/Set/Dictionary Casts + +For Array, Set, or Dictionary types, you can use the casting operators to translate to another instance of the same outer container (Array, Set, or Dictionary respectively) with a different component type. +Note that the following discussion applies only to these specific types. +It does not apply to any other types, nor is there any mechanism to add this behavior to other types. + +Example: Given an `arr` of type `Array`, you can cast `arr as? Array`. +The result will be a new array where each `Int` in the original array has been individually cast to an `Any`. + +However, if any component item cannot be cast, then the outer cast will also fail. +For example, consider the following: +``` +let a: Array = [Int(7), "string"] +a as? Array // Fails because "string" cannot be cast to `Int` +``` + +Specifically, the casting operator acts for `Array` as if it were implemented as follows. +In particular, note that an empty array can be successfully cast to any destination array type. +``` +func arrayCast(source: Array) -> Optional> { + var result = Array() + for t in source { + if let u = t as? U { + result.append(u) + } else { + return nil + } + } + return result +} +``` + +Invariants +* Arrays cast iff their contents do: If `t` is an instance of `T` and `U` is any type, then `t is U == [t] is [U]` +* Empty arrays always cast: If `T` and `U` are any types, `Array() is Array` + +Similar logic applies to `Set` and `Dictionary` casts. +Note that the resulting `Set` or `Dictionary` may have fewer items than the original if the component casting operation converts non-equal items in the source into equal items in the destination. + +Specifically, the casting operator acts on `Set` and `Dictionary` as if by the following code: +``` +func setCast(source: Set) -> Optional> { + var result = Set() + for t in source { + if let u = t as? U { + result.append(u) + } else { + return nil + } + } + return result +} + +func dictionaryCast(source: Dictionary) -> Optional> { + var result = Dictionary() + for (k,v) in source { + if let k2 = k as? K2, v2 = v as? V2 { + result[k2] = v2 + } else { + return nil + } + } + return result +} +``` + +#### Collection Casting performance and `as!` + +For `as?` casts, the casting behavior above requires that every element be converted separately. +This can be a particular bottleneck when trying to share large containers between Swift and Objective-C code. + +However, for `as!` casts, it is the programmer's responsibility to guarantee that the operation will succeed before requesting the conversion. +The implementation is allowed (but not required) to exploit this by deferring the inner component casts until the relevant item is needed. +Such lazy conversion can provide a significant performance improvement in cases where the data is known (by the programmer) to be safe and where the inner component casts are non-trivial. +However, if the conversion cannot be completed, it is indeterminate whether the cast request will fail immediately or whether the program will fail at some later point. + +### Tuples + +Casting from a tuple type T1 to a tuple type T2 will succeed iff the following hold: +* T1 and T2 have the same number of elements +* If an element has a label in both T1 and T2, the labels are identical +* Each element of T1 can be individually cast to the corresponding type of T2 + +### Functions + +Casting from a function type F1 to a function type F2 will succeed iff the following hold: +* The two types have the same number of arguments +* Corresponding arguments have identical types +* The return types are identical +* If F1 is a throwing function type, then F2 must be a throwing function type. If F1 is not throwing, then F2 may be a throwing or non-throwing function type. + +Note that it is _not_ sufficient for argument and return types to be castable; they must actually be identical. + +## Existential Types + +Conceptually, an "existential type" is an opaque wrapper that carries a type and an instance of that type. +The various existential types differ in what kinds of types they can hold (for example, `AnyObject` can only hold reference types) and in the capabilities exposed by the container (`AnyHashable` exposes equality testing and hashing). + +### Any Any Swift instance can be cast to the type `Any`. An instance of `Any` has no useful methods or properties; to utilize the contents, you must cast it to another type. @@ -175,7 +327,7 @@ The requirement that `U` be `Equatable` is a technical necessity for using `==` Note that in many cases, we've shortened such invariants to the form `t is U == (t as! Any) is U`. Using `is` here simply avoids the technical necessity that `U` be `Equatable` but except where explicitly called out, the intention in every case is that such casting does not change the value. -## AnyObject +### AnyObject Any class, enum, struct, tuple, function, metatype, or existential metatype instance can be cast to `AnyObject`. @@ -195,17 +347,20 @@ One example of this is Foundation's `NSNumber` type which conditionally bridges As a result, when Foundation is in scope, `Int(7) is Double == false` but `(Int(7) as! AnyObject) is Double == true`. In general, the ability to add new bridging behaviors from a single type to several distinct types implies that Swift casting cannot be transitive. -## Error (SE-0112) +### Error (SE-0112) Although the Error protocol is specially handled by the Swift compiler and runtime (as detailed in [SE-0112](https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md)), it behaves like an ordinary protocol type for casting purposes. (See "Note: 'Self-conforming' protocols" below for additional details relevant to the Error protocol.) -## AnyHashable (SE-0131) +### AnyHashable (SE-0131) -For casting purposes, `AnyHashable` behaves like a protocol type. +For casting purposes, `AnyHashable` behaves like an existential type. -## Existential/Protocol types +However, note that `AnyHashable` does not act like an existential for other purposes. +For example, it's metatype is named `AnyHashable.Type` and it does not have an existential metatype. + +### Protocol Witness types Caveat: Protocols that have `associatedtype` properties or which make use of the `Self` typealias cannot be used as independent types. @@ -241,83 +396,12 @@ For example, `Optional` conforms to `CustomDebugStringConvertible` but not to `C Casting an optional instance to the first of these protocols will result in an item whose `.debugDescription` will describe the optional instance. Casting an optional instance to the second will provide an instance whose `.description` property describes the inner non-Optional instance. -## Array/Set/Dictionary Casts - -For Array, Set, or Dictionary types, you can use the casting operators to translate to another instance of the same outer container (Array, Set, or Dictionary respectively) with a different component type. -Note that the following discussion applies only to these specific types. -It does not apply to any other types, nor is there any mechanism to add this behavior to other types. - -Example: Given an `arr` of type `Array`, you can cast `arr as? Array`. -The result will be a new array where each `Int` in the original array has been individually cast to an `Any`. - -However, if any component item cannot be cast, then the outer cast will also fail. -For example, consider the following: -``` -let a: Array = [Int(7), "string"] -a as? Array // Fails because "string" cannot be cast to `Int` -``` - -Specifically, the casting operator acts for `Array` as if it were implemented as follows. -In particular, note that an empty array can be successfully cast to any destination array type. -``` -func arrayCast(source: Array) -> Optional> { - var result = Array() - for t in source { - if let u = t as? U { - result.append(u) - } else { - return nil - } - } - return result -} -``` - -Invariants -* Arrays cast iff their contents do: If `t` is an instance of `T` and `U` is any type, then `t is U == [t] is [U]` -* Empty arrays always cast: If `T` and `U` are any types, `Array() is Array` - -Similar logic applies to `Set` and `Dictionary` casts. -Note that the resulting `Set` or `Dictionary` may have fewer items than the original if the component casting operation converts non-equal items in the source into equal items in the destination. - -Specifically, the casting operator acts on `Set` and `Dictionary` as if by the following code: -``` -func setCast(source: Set) -> Optional> { - var result = Set() - for t in source { - if let u = t as? U { - result.append(u) - } else { - return nil - } - } - return result -} - -func dictionaryCast(source: Dictionary) -> Optional> { - var result = Dictionary() - for (k,v) in source { - if let k2 = k as? K2, v2 = v as? V2 { - result[k2] = v2 - } else { - return nil - } - } - return result -} -``` - -### Collection Casting performance and `as!` - -For `as?` casts, the casting behavior above requires that every element be converted separately. -This can be a particular bottleneck when trying to share large containers between Swift and Objective-C code. +## Metatypes -However, for `as!` casts, it is the programmer's responsibility to guarantee that the operation will succeed before requesting the conversion. -The implementation is allowed (but not required) to exploit this by deferring the inner component casts until the relevant item is needed. -Such lazy conversion can provide a significant performance improvement in cases where the data is known (by the programmer) to be safe and where the inner component casts are non-trivial. -However, if the conversion cannot be completed, it is indeterminate whether the cast request will fail immediately or whether the program will fail at some later point. +Swift supports two kinds of metatypes: +In addition to the regular metatypes supported by many other languages, it also has _existential_ metatypes that can be used to access static protocol requirements. -## Metatypes +### Metatypes For every type `T`, there is a unique instance `T.self` that represents the type at runtime. As with all instances, `T.self` has a type. @@ -352,7 +436,7 @@ let s = S() type(of: s) == S.self // always true type(of: S.self) == S.Type.self -// Metatype of a protocol type +// Metatype of a protocol (or other existential) type protocol P {} P.self is P.Protocol // always true // P.Protocol is a metatype, not a protocol, so: @@ -377,7 +461,7 @@ Invariants * Subtypes define metatype subtypes: if `T` and `U` are non-protocol types, `T.self is U.Type == T.Type.self is U.Type.Type` * Subtypes define metatype subtypes: if `T` is a non-protocol type and `P` is a protocol type, `T.self is P.Protocol == T.Type.self is P.Protocol.Type` -## Existential Metatypes +### Existential Metatypes Protocols can specify constraints and provide default implementations for instances of types. They can also specify constraints and provide default implementations for static members of types. @@ -412,7 +496,7 @@ Invariants * Since every type `T` conforms to `Any`, `T.self is Any.Type` is always true * Since every class type `C` conforms to `AnyObject`, `C.self is AnyObject.Type` is always true (this includes Objective-C class types) -### Note: "Self conforming" protocols +### Note: "Self conforming" existential types As mentioned above, a protocol definition for `P` implicitly defines types `P.Type` (the existential metatype) and `P.Protocol` (the metatype). It also defines an associated type called `P` which is the type of a container that can hold any object whose concrete type conforms to the protocol `P`. @@ -438,9 +522,10 @@ let a : P let b : MyGenericType(a) ``` As above, since `a` has type `P`, this code is instantiating `MyGenericType` with `T = P`, which is only valid if `P` conforms to `P`. - Note that any protocol that specifies static methods, static properties, associated types, or initializers cannot possibly be self-conforming. -As of Swift 5.3, the only self-conforming protocols are `Any`, `Error`, and Objective-C protocols that have no static requirements. + +Although the discussion above specifically talks about protocols, it applies equally well to other existential types. +As of Swift 5.3, the only self-conforming existential types are `Any`, `Error`, and Objective-C protocols that have no static requirements. Invariants * `Any` self-conforms: `Any.self is Any.Type == true` @@ -449,64 +534,6 @@ Invariants For example, the last invariant here implies that for any Objective-C protocol `OP` that has no static requirements, `OP.self is AnyObject.Type`. This follows from the fact that `OP` self-conforms and that every Objective-C protocol has `AnyObject` as an implicit parent protocol. -## CoreFoundation types - -* If `CF` is a CoreFoundation type, `cf` is an instance of `CF`, and `NS` is the corresponding Objective-C type, then `cf is NS == true` -* Further, since every Objective-C type inherits from `NSObject`, `cf is NSObject == true` -* In the above situation, if `T` is some other type and `cf is NS == true`, then `cf as! NS is T` iff `cf is T`. - -The intention of the above is to treat instances of CoreFoundation types as being simultaneously instances of the corresponding Objective-C type, in keeping with the general dual nature of these types. -In particular, if a protocol conformance is declared on the Objective-C type, then instances of the CoreFoundation type can be cast to the protocol type directly. - -XXX TODO: Converse? If ObjC instance has CF equivalent and CF type is extended, ... ?? - -## Objective-C types - -The following discussion applies in three different cases: -* _Explicit_ conversions from use of the `is`, `as?`, and `as!` operators. -* _Implicit_ conversions from Swift to Objective-C: These conversions are generated automatically when Swift code calls an Objective-C function or method with an argument that is not already of an Objective-C type, or when a Swift function returns a value to an Objective-C caller. -* _Implicit_ conversions from Objective-C to Swift: These are generated automatically when arguments are passed from an Objective-C caller to a Swift function, or when an Objective-C function returns a value to a Swift caller. -Unless stated otherwise, all of the following cases apply equally to all three of the above cases. - -Explicit casts among Swift and Objective-C class types follow the same general rules described earlier for class types in general. -Likewise, explicitly casting a class instance to an Objective-C protocol type follows the general rules for casts to protocol types. - -XXX TODO EXPLAIN Implicit conversions from Objective-C types to Swift types XXXX. - -CoreFoundation types can be explicitly cast to and from their corresponding Objective-C types as described above. - -Objective-C types and protocols -* `T` is an Objective-C class type iff `T.self is NSObject.Type` -* `P` is an Objective-C protocol iff XXX TODO XXX - -## The `_ObjectiveCBridgeable` Protocol - -The `_ObjectiveCBridgeable` protocol allows certain types to opt into custom casting behavior. -Note that although this mechanism was explicitly designed to simplify Swift interoperability with Objective-C, it is not necessarily tied to Objective-C. - -The `_ObjectiveCBridgeable` protocol defines an associated reference type `_ObjectiveCType`, along with a collection of methods that support casting to and from the associated `_ObjectiveCType`. -This protocol allows library code to provide tailored mechanisms for casting Swift types to reference types. -When casting to `AnyObject`, the casting logic prefers this tailored mechanism to the general `_SwiftValue` container mentioned above. - -Note: The associated `_ObjectiveCType` is constrained to be a subtype of `AnyObject`; it is not limited to being an actual Objective-C type. -In particular, this mechanism is equally available to the Swift implementation of Foundation on non-Apple platforms and the Objective-C Foundation on Apple platforms. - -Example #1: Foundation extends the `Array` type in the standard library with an `_ObjectiveCBridgeable` conformance to `NSArray`. This allows Swift arrays to be cast to and from Foundation `NSArray` instances. -``` -let a = [1, 2, 3] // Array -let b = a as? AnyObject // casts to NSArray -``` - -Example #2: Foundation also extends each Swift numeric type with an `_ObjectiveCBridgeable` conformance to `NSNumber`. -``` -let a = 1 // Int -// After the next line, b is an Optional -// holding a reference to an NSNumber -let b = a as? AnyObject -// NSNumber is bridgeable to Double -let c = b as? Double -``` - ## Implementation Notes Casting operators that appear in source code are translated into SIL in a variety of ways depending on the details of the types involved. From ba6dc1724b9a981eb6c4425a9372f436a4aabef5 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sat, 29 Aug 2020 21:17:59 -0700 Subject: [PATCH 465/663] [semantic-arc] Split load [copy] -> load_borrow opt into its own file. --- lib/SILOptimizer/SemanticARC/CMakeLists.txt | 3 +- .../SemanticARC/LoadCopyToLoadBorrowOpt.cpp | 491 ++++++++++++++++++ .../SemanticARC/SemanticARCOptVisitor.h | 2 + .../SemanticARC/SemanticARCOpts.cpp | 456 ---------------- 4 files changed, 495 insertions(+), 457 deletions(-) create mode 100644 lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt index 91b9e107c5dc8..1291d0660ad69 100644 --- a/lib/SILOptimizer/SemanticARC/CMakeLists.txt +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -1,3 +1,4 @@ target_sources(swiftSILOptimizer PRIVATE SemanticARCOpts.cpp - OwnershipLiveRange.cpp) + OwnershipLiveRange.cpp + LoadCopyToLoadBorrowOpt.cpp) diff --git a/lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp b/lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp new file mode 100644 index 0000000000000..2ea47e47c8315 --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp @@ -0,0 +1,491 @@ +//===--- LoadCopyToLoadBorrowOpt.cpp --------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Defines the main optimization that converts load [copy] -> load_borrow if we +/// can prove that the +1 is not actually needed and the memory loaded from is +/// never written to while the load [copy]'s object value is being used. +/// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-semantic-arc-opts" + +#include "OwnershipLiveRange.h" +#include "SemanticARCOptVisitor.h" +#include "swift/SIL/LinearLifetimeChecker.h" +#include "swift/SIL/MemAccessUtils.h" +#include "swift/SIL/OwnershipUtils.h" +#include "swift/SIL/Projection.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" +#include "llvm/Support/CommandLine.h" + +using namespace swift; +using namespace swift::semanticarc; + +//===----------------------------------------------------------------------===// +// Well Behaved Write Analysis +//===----------------------------------------------------------------------===// + +/// Returns true if we were able to ascertain that either the initialValue has +/// no write uses or all of the write uses were writes that we could understand. +bool swift::semanticarc::constructCacheValue( + SILValue initialValue, + SmallVectorImpl &wellBehavedWriteAccumulator) { + SmallVector worklist(initialValue->getUses()); + + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + SILInstruction *user = op->getUser(); + + if (Projection::isAddressProjection(user) || + isa(user)) { + for (SILValue r : user->getResults()) { + llvm::copy(r->getUses(), std::back_inserter(worklist)); + } + continue; + } + + if (auto *oeai = dyn_cast(user)) { + // Mutable access! + if (oeai->getAccessKind() != OpenedExistentialAccess::Immutable) { + wellBehavedWriteAccumulator.push_back(op); + } + + // Otherwise, look through it and continue. + llvm::copy(oeai->getUses(), std::back_inserter(worklist)); + continue; + } + + if (auto *si = dyn_cast(user)) { + // We must be the dest since addresses can not be stored. + assert(si->getDest() == op->get()); + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Add any destroy_addrs to the resultAccumulator. + if (isa(user)) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // load_borrow and incidental uses are fine as well. + if (isa(user) || isIncidentalUse(user)) { + continue; + } + + // Look through begin_access and mark them/their end_borrow as users. + if (auto *bai = dyn_cast(user)) { + // If we do not have a read, mark this as a write. Also, insert our + // end_access as well. + if (bai->getAccessKind() != SILAccessKind::Read) { + wellBehavedWriteAccumulator.push_back(op); + transform(bai->getUsersOfType(), + std::back_inserter(wellBehavedWriteAccumulator), + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); + } + + // And then add the users to the worklist and continue. + llvm::copy(bai->getUses(), std::back_inserter(worklist)); + continue; + } + + // If we have a load, we just need to mark the load [take] as a write. + if (auto *li = dyn_cast(user)) { + if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take) { + wellBehavedWriteAccumulator.push_back(op); + } + continue; + } + + // If we have a FullApplySite, we need to do per convention/inst logic. + if (auto fas = FullApplySite::isa(user)) { + // Begin by seeing if we have an in_guaranteed use. If we do, we are done. + if (fas.getArgumentConvention(*op) == + SILArgumentConvention::Indirect_In_Guaranteed) { + continue; + } + + // Then see if we have an apply site that is not a coroutine apply + // site. In such a case, without further analysis, we can treat it like an + // instantaneous write and validate that it doesn't overlap with our load + // [copy]. + if (!fas.beginsCoroutineEvaluation() && + fas.getArgumentConvention(*op).isInoutConvention()) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Otherwise, be conservative and return that we had a write that we did + // not understand. + LLVM_DEBUG(llvm::dbgs() + << "Function: " << user->getFunction()->getName() << "\n"); + LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); + LLVM_DEBUG(llvm::dbgs() << "Unhandled apply site!: " << *user); + + return false; + } + + // Copy addr that read are just loads. + if (auto *cai = dyn_cast(user)) { + // If our value is the destination, this is a write. + if (cai->getDest() == op->get()) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Ok, so we are Src by process of elimination. Make sure we are not being + // taken. + if (cai->isTakeOfSrc()) { + wellBehavedWriteAccumulator.push_back(op); + continue; + } + + // Otherwise, we are safe and can continue. + continue; + } + + // If we did not recognize the user, just return conservatively that it was + // written to in a way we did not understand. + LLVM_DEBUG(llvm::dbgs() + << "Function: " << user->getFunction()->getName() << "\n"); + LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); + LLVM_DEBUG(llvm::dbgs() << "Unknown instruction!: " << *user); + return false; + } + + // Ok, we finished our worklist and this address is not being written to. + return true; +} + +//===----------------------------------------------------------------------===// +// Memory Analysis +//===----------------------------------------------------------------------===// + +namespace { + +/// A class that computes in a flow insensitive way if we can prove that our +/// storage is either never written to, or is initialized exactly once and never +/// written to again. In both cases, we can convert load [copy] -> load_borrow +/// safely. +class StorageGuaranteesLoadVisitor + : public AccessUseDefChainVisitor { + // The outer SemanticARCOptVisitor. + SemanticARCOptVisitor &ARCOpt; + + // The live range of the original load. + const OwnershipLiveRange &liveRange; + + // The current address being visited. + SILValue currentAddress; + + Optional isWritten; + +public: + StorageGuaranteesLoadVisitor(SemanticARCOptVisitor &arcOpt, LoadInst *load, + const OwnershipLiveRange &liveRange) + : ARCOpt(arcOpt), liveRange(liveRange), + currentAddress(load->getOperand()) {} + + void answer(bool written) { + currentAddress = nullptr; + isWritten = written; + } + + void next(SILValue address) { currentAddress = address; } + + void visitNestedAccess(BeginAccessInst *access) { + // First see if we have read/modify. If we do not, just look through the + // nested access. + switch (access->getAccessKind()) { + case SILAccessKind::Init: + case SILAccessKind::Deinit: + return next(access->getOperand()); + case SILAccessKind::Read: + case SILAccessKind::Modify: + break; + } + + // Next check if our live range is completely in the begin/end access + // scope. If so, we may be able to use a load_borrow here! + SmallVector endScopeUses; + transform(access->getEndAccesses(), std::back_inserter(endScopeUses), + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); + SmallPtrSet visitedBlocks; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + if (!checker.validateLifetime(access, endScopeUses, + liveRange.getAllConsumingUses())) { + // If we fail the linear lifetime check, then just recur: + return next(access->getOperand()); + } + + // Otherwise, if we have read, then we are done! + if (access->getAccessKind() == SILAccessKind::Read) { + return answer(false); + } + + // If we have a modify, check if our value is /ever/ written to. If it is + // never actually written to, then we convert to a load_borrow. + auto result = ARCOpt.addressToExhaustiveWriteListCache.get(access); + if (!result.hasValue()) { + return answer(true); + } + + if (result.getValue().empty()) { + return answer(false); + } + + return answer(true); + } + + void visitArgumentAccess(SILFunctionArgument *arg) { + // If this load_copy is from an indirect in_guaranteed argument, then we + // know for sure that it will never be written to. + if (arg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed)) { + return answer(false); + } + + // If we have an inout parameter that isn't ever actually written to, return + // false. + if (arg->getKnownParameterInfo().isIndirectMutating()) { + auto wellBehavedWrites = + ARCOpt.addressToExhaustiveWriteListCache.get(arg); + if (!wellBehavedWrites.hasValue()) { + return answer(true); + } + + // No writes. + if (wellBehavedWrites->empty()) { + return answer(false); + } + + // Ok, we have some writes. See if any of them are within our live + // range. If any are, we definitely can not promote to load_borrow. + SmallPtrSet visitedBlocks; + SmallVector foundBeginAccess; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + SILValue introducerValue = liveRange.getIntroducer().value; + if (!checker.usesNotContainedWithinLifetime(introducerValue, + liveRange.getDestroyingUses(), + *wellBehavedWrites)) { + return answer(true); + } + + // Finally, check if our live range is strictly contained within any of + // our scoped writes. + SmallVector endAccessList; + for (Operand *use : *wellBehavedWrites) { + auto *bai = dyn_cast(use->getUser()); + if (!bai) { + continue; + } + + endAccessList.clear(); + llvm::transform( + bai->getUsersOfType(), + std::back_inserter(endAccessList), + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); + visitedBlocks.clear(); + + // We know that our live range is based on a load [copy], so we know + // that our value must have a defining inst. + auto *definingInst = + cast(introducerValue->getDefiningInstruction()); + + // Then if our defining inst is not in our bai, endAccessList region, we + // know that the two ranges must be disjoint, so continue. + if (!checker.validateLifetime(bai, endAccessList, + &definingInst->getAllOperands()[0])) { + continue; + } + + // Otherwise, we do have an overlap, return true. + return answer(true); + } + + // Otherwise, there isn't an overlap, so we don't write to it. + return answer(false); + } + + // TODO: This should be extended: + // + // 1. We should be able to analyze in arguments and see if they are only + // ever destroyed at the end of the function. In such a case, we may be + // able to also to promote load [copy] from such args to load_borrow. + return answer(true); + } + + void visitGlobalAccess(SILValue global) { + return answer(!AccessedStorage(global, AccessedStorage::Global) + .isLetAccess(&ARCOpt.F)); + } + + void visitClassAccess(RefElementAddrInst *field) { + currentAddress = nullptr; + + // We know a let property won't be written to if the base object is + // guaranteed for the duration of the access. + // For non-let properties conservatively assume they may be written to. + if (!field->getField()->isLet()) { + return answer(true); + } + + // The lifetime of the `let` is guaranteed if it's dominated by the + // guarantee on the base. See if we can find a single borrow introducer for + // this object. If we could not find a single such borrow introducer, assume + // that our property is conservatively written to. + SILValue baseObject = field->getOperand(); + auto value = getSingleBorrowIntroducingValue(baseObject); + if (!value) { + return answer(true); + } + + // Ok, we have a single borrow introducing value. First do a quick check if + // we have a non-local scope that is a function argument. In such a case, we + // know statically that our let can not be written to in the current + // function. To be conservative, assume that all other non-local scopes + // write to memory. + if (!value->isLocalScope()) { + if (value->kind == BorrowedValueKind::SILFunctionArgument) { + return answer(false); + } + + // TODO: Once we model Coroutine results as non-local scopes, we should be + // able to return false here for them as well. + return answer(true); + } + + // TODO: This is disabled temporarily for guaranteed phi args just for + // staging purposes. Thus be conservative and assume true in these cases. + if (value->kind == BorrowedValueKind::Phi) { + return answer(true); + } + + // Ok, we now know that we have a local scope whose lifetime we need to + // analyze. With that in mind, gather up the lifetime ending uses of our + // borrow scope introducing value and then use the linear lifetime checker + // to check whether the copied value is dominated by the lifetime of the + // borrow it's based on. + SmallVector endScopeInsts; + value->visitLocalScopeEndingUses( + [&](Operand *use) { endScopeInsts.push_back(use); }); + + SmallPtrSet visitedBlocks; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + + // Returns true on success. So we invert. + bool foundError = !checker.validateLifetime( + baseObject, endScopeInsts, liveRange.getAllConsumingUses()); + return answer(foundError); + } + + // TODO: Handle other access kinds? + void visitBase(SILValue base, AccessedStorage::Kind kind) { + return answer(true); + } + + void visitNonAccess(SILValue addr) { return answer(true); } + + void visitCast(SingleValueInstruction *cast, Operand *parentAddr) { + return next(parentAddr->get()); + } + + void visitPathComponent(SingleValueInstruction *projectedAddr, + Operand *parentAddr) { + return next(parentAddr->get()); + } + + void visitPhi(SILPhiArgument *phi) { + // We shouldn't have address phis in OSSA SIL, so we don't need to recur + // through the predecessors here. + return answer(true); + } + + /// See if we have an alloc_stack that is only written to once by an + /// initializing instruction. + void visitStackAccess(AllocStackInst *stack) { + SmallVector destroyAddrOperands; + bool initialAnswer = isSingleInitAllocStack(stack, destroyAddrOperands); + if (!initialAnswer) + return answer(true); + + // Then make sure that all of our load [copy] uses are within the + // destroy_addr. + SmallPtrSet visitedBlocks; + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + // Returns true on success. So we invert. + bool foundError = !checker.validateLifetime( + stack, destroyAddrOperands /*consuming users*/, + liveRange.getAllConsumingUses() /*non consuming users*/); + return answer(foundError); + } + + bool doIt() { + while (currentAddress) { + visit(currentAddress); + } + return *isWritten; + } +}; + +} // namespace + +bool SemanticARCOptVisitor::isWrittenTo(LoadInst *load, + const OwnershipLiveRange &lr) { + StorageGuaranteesLoadVisitor visitor(*this, load, lr); + return visitor.doIt(); +} + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +// Convert a load [copy] from unique storage [read] that has all uses that can +// accept a guaranteed parameter to a load_borrow. +bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) { + // This optimization can use more complex analysis. We should do some + // experiments before enabling this by default as a guaranteed optimization. + if (onlyGuaranteedOpts) + return false; + + if (li->getOwnershipQualifier() != LoadOwnershipQualifier::Copy) + return false; + + // Ok, we have our load [copy]. Make sure its value is truly a dead live range + // implying it is only ever consumed by destroy_value instructions. If it is + // consumed, we need to pass off a +1 value, so bail. + // + // FIXME: We should consider if it is worth promoting a load [copy] + // -> load_borrow if we can put a copy_value on a cold path and thus + // eliminate RR traffic on a hot path. + OwnershipLiveRange lr(li); + if (bool(lr.hasUnknownConsumingUse())) + return false; + + // Then check if our address is ever written to. If it is, then we cannot use + // the load_borrow because the stored value may be released during the loaded + // value's live range. + if (isWrittenTo(li, lr)) + return false; + + // Ok, we can perform our optimization. Convert the load [copy] into a + // load_borrow. + auto *lbi = + SILBuilderWithScope(li).createLoadBorrow(li->getLoc(), li->getOperand()); + + lr.insertEndBorrowsAtDestroys(lbi, getDeadEndBlocks(), lifetimeFrontier); + std::move(lr).convertToGuaranteedAndRAUW(lbi, getCallbacks()); + return true; +} diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h index fce6908ae6252..7a8be8ea7982d 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h @@ -13,6 +13,8 @@ #ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H #define SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H +#include "OwnershipLiveRange.h" + #include "swift/Basic/BlotSetVector.h" #include "swift/Basic/FrozenMultiMap.h" #include "swift/Basic/MultiMapCache.h" diff --git a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index b501ed7e64cff..431716a388ad6 100644 --- a/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -45,150 +45,10 @@ using namespace swift; using namespace swift::semanticarc; -//===----------------------------------------------------------------------===// -// Address Written To Analysis -//===----------------------------------------------------------------------===// - -/// Returns true if we were able to ascertain that either the initialValue has -/// no write uses or all of the write uses were writes that we could understand. -bool swift::semanticarc::constructCacheValue( - SILValue initialValue, - SmallVectorImpl &wellBehavedWriteAccumulator) { - SmallVector worklist(initialValue->getUses()); - - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - SILInstruction *user = op->getUser(); - - if (Projection::isAddressProjection(user) || - isa(user)) { - for (SILValue r : user->getResults()) { - llvm::copy(r->getUses(), std::back_inserter(worklist)); - } - continue; - } - - if (auto *oeai = dyn_cast(user)) { - // Mutable access! - if (oeai->getAccessKind() != OpenedExistentialAccess::Immutable) { - wellBehavedWriteAccumulator.push_back(op); - } - - // Otherwise, look through it and continue. - llvm::copy(oeai->getUses(), std::back_inserter(worklist)); - continue; - } - - if (auto *si = dyn_cast(user)) { - // We must be the dest since addresses can not be stored. - assert(si->getDest() == op->get()); - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Add any destroy_addrs to the resultAccumulator. - if (isa(user)) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // load_borrow and incidental uses are fine as well. - if (isa(user) || isIncidentalUse(user)) { - continue; - } - - // Look through begin_access and mark them/their end_borrow as users. - if (auto *bai = dyn_cast(user)) { - // If we do not have a read, mark this as a write. Also, insert our - // end_access as well. - if (bai->getAccessKind() != SILAccessKind::Read) { - wellBehavedWriteAccumulator.push_back(op); - transform(bai->getUsersOfType(), - std::back_inserter(wellBehavedWriteAccumulator), - [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); - } - - // And then add the users to the worklist and continue. - llvm::copy(bai->getUses(), std::back_inserter(worklist)); - continue; - } - - // If we have a load, we just need to mark the load [take] as a write. - if (auto *li = dyn_cast(user)) { - if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take) { - wellBehavedWriteAccumulator.push_back(op); - } - continue; - } - - // If we have a FullApplySite, we need to do per convention/inst logic. - if (auto fas = FullApplySite::isa(user)) { - // Begin by seeing if we have an in_guaranteed use. If we do, we are done. - if (fas.getArgumentConvention(*op) == - SILArgumentConvention::Indirect_In_Guaranteed) { - continue; - } - - // Then see if we have an apply site that is not a coroutine apply - // site. In such a case, without further analysis, we can treat it like an - // instantaneous write and validate that it doesn't overlap with our load - // [copy]. - if (!fas.beginsCoroutineEvaluation() && - fas.getArgumentConvention(*op).isInoutConvention()) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Otherwise, be conservative and return that we had a write that we did - // not understand. - LLVM_DEBUG(llvm::dbgs() - << "Function: " << user->getFunction()->getName() << "\n"); - LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); - LLVM_DEBUG(llvm::dbgs() << "Unhandled apply site!: " << *user); - - return false; - } - - // Copy addr that read are just loads. - if (auto *cai = dyn_cast(user)) { - // If our value is the destination, this is a write. - if (cai->getDest() == op->get()) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Ok, so we are Src by process of elimination. Make sure we are not being - // taken. - if (cai->isTakeOfSrc()) { - wellBehavedWriteAccumulator.push_back(op); - continue; - } - - // Otherwise, we are safe and can continue. - continue; - } - - // If we did not recognize the user, just return conservatively that it was - // written to in a way we did not understand. - LLVM_DEBUG(llvm::dbgs() - << "Function: " << user->getFunction()->getName() << "\n"); - LLVM_DEBUG(llvm::dbgs() << "Value: " << op->get()); - LLVM_DEBUG(llvm::dbgs() << "Unknown instruction!: " << *user); - return false; - } - - // Ok, we finished our worklist and this address is not being written to. - return true; -} - //===----------------------------------------------------------------------===// // Implementation //===----------------------------------------------------------------------===// -namespace { - -} // end anonymous namespace - static llvm::cl::opt VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", llvm::cl::init(false), llvm::cl::Hidden); @@ -997,322 +857,6 @@ bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) { return false; } -//===----------------------------------------------------------------------===// -// load [copy] Optimizations -//===----------------------------------------------------------------------===// - -namespace { - -/// A class that computes in a flow insensitive way if we can prove that our -/// storage is either never written to, or is initialized exactly once and never -/// written to again. In both cases, we can convert load [copy] -> load_borrow -/// safely. -class StorageGuaranteesLoadVisitor - : public AccessUseDefChainVisitor { - // The outer SemanticARCOptVisitor. - SemanticARCOptVisitor &ARCOpt; - - // The live range of the original load. - const OwnershipLiveRange &liveRange; - - // The current address being visited. - SILValue currentAddress; - - Optional isWritten; - -public: - StorageGuaranteesLoadVisitor(SemanticARCOptVisitor &arcOpt, LoadInst *load, - const OwnershipLiveRange &liveRange) - : ARCOpt(arcOpt), liveRange(liveRange), - currentAddress(load->getOperand()) {} - - void answer(bool written) { - currentAddress = nullptr; - isWritten = written; - } - - void next(SILValue address) { currentAddress = address; } - - void visitNestedAccess(BeginAccessInst *access) { - // First see if we have read/modify. If we do not, just look through the - // nested access. - switch (access->getAccessKind()) { - case SILAccessKind::Init: - case SILAccessKind::Deinit: - return next(access->getOperand()); - case SILAccessKind::Read: - case SILAccessKind::Modify: - break; - } - - // Next check if our live range is completely in the begin/end access - // scope. If so, we may be able to use a load_borrow here! - SmallVector endScopeUses; - transform(access->getEndAccesses(), std::back_inserter(endScopeUses), - [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); - SmallPtrSet visitedBlocks; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - if (!checker.validateLifetime(access, endScopeUses, - liveRange.getAllConsumingUses())) { - // If we fail the linear lifetime check, then just recur: - return next(access->getOperand()); - } - - // Otherwise, if we have read, then we are done! - if (access->getAccessKind() == SILAccessKind::Read) { - return answer(false); - } - - // If we have a modify, check if our value is /ever/ written to. If it is - // never actually written to, then we convert to a load_borrow. - auto result = ARCOpt.addressToExhaustiveWriteListCache.get(access); - if (!result.hasValue()) { - return answer(true); - } - - if (result.getValue().empty()) { - return answer(false); - } - - return answer(true); - } - - void visitArgumentAccess(SILFunctionArgument *arg) { - // If this load_copy is from an indirect in_guaranteed argument, then we - // know for sure that it will never be written to. - if (arg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed)) { - return answer(false); - } - - // If we have an inout parameter that isn't ever actually written to, return - // false. - if (arg->getKnownParameterInfo().isIndirectMutating()) { - auto wellBehavedWrites = - ARCOpt.addressToExhaustiveWriteListCache.get(arg); - if (!wellBehavedWrites.hasValue()) { - return answer(true); - } - - // No writes. - if (wellBehavedWrites->empty()) { - return answer(false); - } - - // Ok, we have some writes. See if any of them are within our live - // range. If any are, we definitely can not promote to load_borrow. - SmallPtrSet visitedBlocks; - SmallVector foundBeginAccess; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - SILValue introducerValue = liveRange.getIntroducer().value; - if (!checker.usesNotContainedWithinLifetime(introducerValue, - liveRange.getDestroyingUses(), - *wellBehavedWrites)) { - return answer(true); - } - - // Finally, check if our live range is strictly contained within any of - // our scoped writes. - SmallVector endAccessList; - for (Operand *use : *wellBehavedWrites) { - auto *bai = dyn_cast(use->getUser()); - if (!bai) { - continue; - } - - endAccessList.clear(); - llvm::transform( - bai->getUsersOfType(), - std::back_inserter(endAccessList), - [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); - visitedBlocks.clear(); - - // We know that our live range is based on a load [copy], so we know - // that our value must have a defining inst. - auto *definingInst = - cast(introducerValue->getDefiningInstruction()); - - // Then if our defining inst is not in our bai, endAccessList region, we - // know that the two ranges must be disjoint, so continue. - if (!checker.validateLifetime(bai, endAccessList, - &definingInst->getAllOperands()[0])) { - continue; - } - - // Otherwise, we do have an overlap, return true. - return answer(true); - } - - // Otherwise, there isn't an overlap, so we don't write to it. - return answer(false); - } - - // TODO: This should be extended: - // - // 1. We should be able to analyze in arguments and see if they are only - // ever destroyed at the end of the function. In such a case, we may be - // able to also to promote load [copy] from such args to load_borrow. - return answer(true); - } - - void visitGlobalAccess(SILValue global) { - return answer(!AccessedStorage(global, AccessedStorage::Global) - .isLetAccess(&ARCOpt.F)); - } - - void visitClassAccess(RefElementAddrInst *field) { - currentAddress = nullptr; - - // We know a let property won't be written to if the base object is - // guaranteed for the duration of the access. - // For non-let properties conservatively assume they may be written to. - if (!field->getField()->isLet()) { - return answer(true); - } - - // The lifetime of the `let` is guaranteed if it's dominated by the - // guarantee on the base. See if we can find a single borrow introducer for - // this object. If we could not find a single such borrow introducer, assume - // that our property is conservatively written to. - SILValue baseObject = field->getOperand(); - auto value = getSingleBorrowIntroducingValue(baseObject); - if (!value) { - return answer(true); - } - - // Ok, we have a single borrow introducing value. First do a quick check if - // we have a non-local scope that is a function argument. In such a case, we - // know statically that our let can not be written to in the current - // function. To be conservative, assume that all other non-local scopes - // write to memory. - if (!value->isLocalScope()) { - if (value->kind == BorrowedValueKind::SILFunctionArgument) { - return answer(false); - } - - // TODO: Once we model Coroutine results as non-local scopes, we should be - // able to return false here for them as well. - return answer(true); - } - - // TODO: This is disabled temporarily for guaranteed phi args just for - // staging purposes. Thus be conservative and assume true in these cases. - if (value->kind == BorrowedValueKind::Phi) { - return answer(true); - } - - // Ok, we now know that we have a local scope whose lifetime we need to - // analyze. With that in mind, gather up the lifetime ending uses of our - // borrow scope introducing value and then use the linear lifetime checker - // to check whether the copied value is dominated by the lifetime of the - // borrow it's based on. - SmallVector endScopeInsts; - value->visitLocalScopeEndingUses( - [&](Operand *use) { endScopeInsts.push_back(use); }); - - SmallPtrSet visitedBlocks; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - - // Returns true on success. So we invert. - bool foundError = !checker.validateLifetime( - baseObject, endScopeInsts, liveRange.getAllConsumingUses()); - return answer(foundError); - } - - // TODO: Handle other access kinds? - void visitBase(SILValue base, AccessedStorage::Kind kind) { - return answer(true); - } - - void visitNonAccess(SILValue addr) { return answer(true); } - - void visitCast(SingleValueInstruction *cast, Operand *parentAddr) { - return next(parentAddr->get()); - } - - void visitPathComponent(SingleValueInstruction *projectedAddr, - Operand *parentAddr) { - return next(parentAddr->get()); - } - - void visitPhi(SILPhiArgument *phi) { - // We shouldn't have address phis in OSSA SIL, so we don't need to recur - // through the predecessors here. - return answer(true); - } - - /// See if we have an alloc_stack that is only written to once by an - /// initializing instruction. - void visitStackAccess(AllocStackInst *stack) { - SmallVector destroyAddrOperands; - bool initialAnswer = isSingleInitAllocStack(stack, destroyAddrOperands); - if (!initialAnswer) - return answer(true); - - // Then make sure that all of our load [copy] uses are within the - // destroy_addr. - SmallPtrSet visitedBlocks; - LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); - // Returns true on success. So we invert. - bool foundError = !checker.validateLifetime( - stack, destroyAddrOperands /*consuming users*/, - liveRange.getAllConsumingUses() /*non consuming users*/); - return answer(foundError); - } - - bool doIt() { - while (currentAddress) { - visit(currentAddress); - } - return *isWritten; - } -}; - -} // namespace - -bool SemanticARCOptVisitor::isWrittenTo(LoadInst *load, - const OwnershipLiveRange &lr) { - StorageGuaranteesLoadVisitor visitor(*this, load, lr); - return visitor.doIt(); -} - -// Convert a load [copy] from unique storage [read] that has all uses that can -// accept a guaranteed parameter to a load_borrow. -bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) { - // This optimization can use more complex analysis. We should do some - // experiments before enabling this by default as a guaranteed optimization. - if (onlyGuaranteedOpts) - return false; - - if (li->getOwnershipQualifier() != LoadOwnershipQualifier::Copy) - return false; - - // Ok, we have our load [copy]. Make sure its value is truly a dead live range - // implying it is only ever consumed by destroy_value instructions. If it is - // consumed, we need to pass off a +1 value, so bail. - // - // FIXME: We should consider if it is worth promoting a load [copy] - // -> load_borrow if we can put a copy_value on a cold path and thus - // eliminate RR traffic on a hot path. - OwnershipLiveRange lr(li); - if (bool(lr.hasUnknownConsumingUse())) - return false; - - // Then check if our address is ever written to. If it is, then we cannot use - // the load_borrow because the stored value may be released during the loaded - // value's live range. - if (isWrittenTo(li, lr)) - return false; - - // Ok, we can perform our optimization. Convert the load [copy] into a - // load_borrow. - auto *lbi = - SILBuilderWithScope(li).createLoadBorrow(li->getLoc(), li->getOperand()); - - lr.insertEndBorrowsAtDestroys(lbi, getDeadEndBlocks(), lifetimeFrontier); - std::move(lr).convertToGuaranteedAndRAUW(lbi, getCallbacks()); - return true; -} - //===----------------------------------------------------------------------===// // Top Level Entrypoint //===----------------------------------------------------------------------===// From 62bae423b5b052277801882945865740ec837f70 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Mon, 31 Aug 2020 10:56:47 -0700 Subject: [PATCH 466/663] Un-XFAIL a test that now passes protocol_lookup_foreign exercises CF casting that used to be broken, but now works with the new dynamic casting implementation. --- test/Interpreter/SDK/protocol_lookup_foreign.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/Interpreter/SDK/protocol_lookup_foreign.swift b/test/Interpreter/SDK/protocol_lookup_foreign.swift index f0565dc042a65..ae864b08efc1e 100644 --- a/test/Interpreter/SDK/protocol_lookup_foreign.swift +++ b/test/Interpreter/SDK/protocol_lookup_foreign.swift @@ -4,11 +4,6 @@ // REQUIRES: objc_interop // REQUIRES: OS=macosx -// rdar://20990451 is tracking the fix for compiling this test optimized. -// XFAIL: swift_test_mode_optimize -// XFAIL: swift_test_mode_optimize_size -// XFAIL: swift_test_mode_optimize_unchecked - import Foundation import StdlibUnittest From 55e77785dfacdcfcecad801faaa2a38b4bbec6fb Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Mon, 31 Aug 2020 09:54:05 -0700 Subject: [PATCH 467/663] ABI checker: add a mechansim for specifying allowd ABI breakages When the checker found a breakage listed in the user-specified list, the breage should be consumed internally without failing the check. rdar://68086477 --- include/swift/AST/DiagnosticsModuleDiffer.def | 4 +- include/swift/ClangImporter/ClangImporter.h | 1 + lib/ClangImporter/ClangImporter.cpp | 24 ++++++ test/api-digester/breakage-allowlist.swift | 38 +++++++++ .../ModuleDiagsConsumer.cpp | 27 +++++- .../swift-api-digester/ModuleDiagsConsumer.h | 24 ++++++ .../swift-api-digester/swift-api-digester.cpp | 84 +++++++++++++------ 7 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 test/api-digester/breakage-allowlist.swift diff --git a/include/swift/AST/DiagnosticsModuleDiffer.def b/include/swift/AST/DiagnosticsModuleDiffer.def index d4aba30553186..dbcc194ba4ca6 100644 --- a/include/swift/AST/DiagnosticsModuleDiffer.def +++ b/include/swift/AST/DiagnosticsModuleDiffer.def @@ -74,7 +74,7 @@ ERROR(param_ownership_change,none,"%0 has %1 changing from %2 to %3", (StringRef ERROR(type_witness_change,none,"%0 has type witness type for %1 changing from %2 to %3", (StringRef, StringRef, StringRef, StringRef)) -ERROR(decl_new_witness_table_entry,none,"%0 now requires %select{|no}1 new witness table entry", (StringRef, bool)) +ERROR(decl_new_witness_table_entry,none,"%0 now requires%select{| no}1 new witness table entry", (StringRef, bool)) ERROR(new_decl_without_intro,none,"%0 is a new API without @available attribute", (StringRef)) @@ -88,5 +88,7 @@ ERROR(not_inheriting_convenience_inits,none,"%0 no longer inherits convenience i ERROR(enum_case_added,none,"%0 has been added as a new enum case", (StringRef)) +WARNING(cannot_read_allowlist,none,"cannot read breakage allowlist at '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 128886f6c0bed..a2733ffffeca3 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -378,6 +378,7 @@ class ClangImporter final : public ClangModuleLoader { /// construction of the replica. bool dumpPrecompiledModule(StringRef modulePath, StringRef outputPath); + bool runPreprocessor(StringRef inputPath, StringRef outputPath); const clang::Module *getClangOwningModule(ClangNode Node) const; bool hasTypedef(const clang::Decl *typeDecl) const; diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index e1f1ad590b202..3ec0473562c69 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -1597,6 +1597,30 @@ ClangImporter::emitBridgingPCH(StringRef headerPath, return false; } +bool ClangImporter::runPreprocessor(StringRef inputPath, StringRef outputPath) { + auto emitInstance = cloneCompilerInstanceForPrecompiling(); + auto &invocation = emitInstance->getInvocation(); + auto LangOpts = invocation.getLangOpts(); + auto &OutputOpts = invocation.getPreprocessorOutputOpts(); + OutputOpts.ShowCPP = 1; + OutputOpts.ShowComments = 0; + OutputOpts.ShowLineMarkers = 0; + OutputOpts.ShowMacros = 0; + OutputOpts.ShowMacroComments = 0; + auto language = getLanguageFromOptions(LangOpts); + auto inputFile = clang::FrontendInputFile(inputPath, language); + + auto &FrontendOpts = invocation.getFrontendOpts(); + FrontendOpts.Inputs = {inputFile}; + FrontendOpts.OutputFile = outputPath.str(); + FrontendOpts.ProgramAction = clang::frontend::PrintPreprocessedInput; + + auto action = wrapActionForIndexingIfEnabled( + FrontendOpts, std::make_unique()); + emitInstance->ExecuteAction(*action); + return emitInstance->getDiagnostics().hasErrorOccurred(); +} + bool ClangImporter::emitPrecompiledModule(StringRef moduleMapPath, StringRef moduleName, StringRef outputPath) { diff --git a/test/api-digester/breakage-allowlist.swift b/test/api-digester/breakage-allowlist.swift new file mode 100644 index 0000000000000..9bb5aa7af626c --- /dev/null +++ b/test/api-digester/breakage-allowlist.swift @@ -0,0 +1,38 @@ +// REQUIRES: VENDOR=apple + +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t.mod1) +// RUN: %empty-directory(%t.mod2) +// RUN: %empty-directory(%t.sdk) +// RUN: %empty-directory(%t.module-cache) +// RUN: %empty-directory(%t.baseline/ABI) + +// RUN: echo "public func foo() {}" > %t.mod1/Foo.swift +// RUN: echo "public func bar() {}" > %t.mod2/Foo.swift + +// RUN: echo "Foo: Func foo() has been removed" > %t/incomplete-allowlist.txt +// RUN: echo "Foo: Func foo() has been removed" > %t/complete-allowlist.txt +// RUN: echo "Foo: Func bar() is a new API without @available attribute" >> %t/complete-allowlist.txt + +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-module -o %t.mod1/Foo.swiftmodule %t.mod1/Foo.swift -parse-as-library -enable-library-evolution -emit-module-source-info -emit-module-source-info-path %t.mod1/Foo.swiftsourceinfo -emit-module-interface-path %t.mod1/Foo.swiftinterface -module-name Foo -swift-version 5 + +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-module -o %t.mod2/Foo.swiftmodule %t.mod2/Foo.swift -parse-as-library -enable-library-evolution -emit-module-source-info -emit-module-source-info-path %t.mod2/Foo.swiftsourceinfo -emit-module-interface-path %t.mod2/Foo.swiftinterface -module-name Foo -swift-version 5 + +// RUN: %api-digester -dump-sdk -module Foo -output-dir %t.baseline -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod1 -abi -use-interface-for-module Foo + +// RUN: %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -breakage-allowlist-path %t/complete-allowlist.txt -o %t/expected-diags.txt + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -compiler-style-diags + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -compiler-style-diags -breakage-allowlist-path %t/incomplete-allowlist.txt + +// RUN: %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -compiler-style-diags -breakage-allowlist-path %t/complete-allowlist.txt + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -serialize-diagnostics-path %t/serialized-diag.dia +// RUN: ls %t/serialized-diag.dia + +// RUN: not %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -serialize-diagnostics-path %t/serialized-diag.dia -breakage-allowlist-path %t/incomplete-allowlist.txt +// RUN: ls %t/serialized-diag.dia + +// RUN: %api-digester -diagnose-sdk -print-module -baseline-dir %t.baseline -module Foo -I %t.mod2 -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -serialize-diagnostics-path %t/serialized-diag.dia -breakage-allowlist-path %t/complete-allowlist.txt +// RUN: ls %t/serialized-diag.dia diff --git a/tools/swift-api-digester/ModuleDiagsConsumer.cpp b/tools/swift-api-digester/ModuleDiagsConsumer.cpp index 6e4d2b9dcbd52..7ded7259b744e 100644 --- a/tools/swift-api-digester/ModuleDiagsConsumer.cpp +++ b/tools/swift-api-digester/ModuleDiagsConsumer.cpp @@ -78,7 +78,7 @@ static StringRef getCategoryName(uint32_t ID) { case LocalDiagID::not_inheriting_convenience_inits: return "/* Class Inheritance Change */"; default: - return StringRef(); + return "/* Others */"; } } } @@ -122,3 +122,28 @@ swift::ide::api::ModuleDifferDiagsConsumer::~ModuleDifferDiagsConsumer() { } } } + +bool swift::ide::api:: +FilteringDiagnosticConsumer::shouldProceed(const DiagnosticInfo &Info) { + if (allowedBreakages->empty()) { + return true; + } + llvm::SmallString<256> Text; + { + llvm::raw_svector_ostream Out(Text); + DiagnosticEngine::formatDiagnosticText(Out, Info.FormatString, + Info.FormatArgs); + } + return allowedBreakages->count(Text.str()) == 0; +} + +void swift::ide::api:: +FilteringDiagnosticConsumer::handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) { + if (shouldProceed(Info)) { + if (Info.Kind == DiagnosticKind::Error) { + HasError = true; + } + subConsumer->handleDiagnostic(SM, Info); + } +} diff --git a/tools/swift-api-digester/ModuleDiagsConsumer.h b/tools/swift-api-digester/ModuleDiagsConsumer.h index df83c808baa88..cb23ef5d301ea 100644 --- a/tools/swift-api-digester/ModuleDiagsConsumer.h +++ b/tools/swift-api-digester/ModuleDiagsConsumer.h @@ -41,6 +41,30 @@ class ModuleDifferDiagsConsumer: public PrintingDiagnosticConsumer { ~ModuleDifferDiagsConsumer(); void handleDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override; }; + +class FilteringDiagnosticConsumer: public DiagnosticConsumer { + bool HasError = false; + std::unique_ptr subConsumer; + std::unique_ptr> allowedBreakages; + bool shouldProceed(const DiagnosticInfo &Info); +public: + FilteringDiagnosticConsumer(std::unique_ptr subConsumer, + std::unique_ptr> allowedBreakages): + subConsumer(std::move(subConsumer)), + allowedBreakages(std::move(allowedBreakages)) {} + ~FilteringDiagnosticConsumer() = default; + + bool finishProcessing() override { return subConsumer->finishProcessing(); } + bool hasError() const { return HasError; } + void flush() override { subConsumer->flush(); } + + void informDriverOfIncompleteBatchModeCompilation() override { + subConsumer->informDriverOfIncompleteBatchModeCompilation(); + } + + void handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) override; +}; } } } diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index ed3c61d7623c9..b6ba713b59416 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -264,6 +264,11 @@ SerializedDiagPath("serialize-diagnostics-path", llvm::cl::desc("Serialize diagnostics to a path"), llvm::cl::cat(Category)); +static llvm::cl::opt +BreakageAllowlistPath("breakage-allowlist-path", + llvm::cl::desc("An allowlist of breakages to not complain about"), + llvm::cl::cat(Category)); + } // namespace options namespace { @@ -2320,6 +2325,50 @@ createDiagConsumer(llvm::raw_ostream &OS, bool &FailOnError) { } } +static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) { + auto FileBufOrErr = llvm::MemoryBuffer::getFile(Path); + if (!FileBufOrErr) { + llvm::errs() << "error opening file '" << Path << "': " + << FileBufOrErr.getError().message() << '\n'; + return 1; + } + + StringRef BufferText = FileBufOrErr.get()->getBuffer(); + while (!BufferText.empty()) { + StringRef Line; + std::tie(Line, BufferText) = BufferText.split('\n'); + Line = Line.trim(); + if (Line.empty()) + continue; + if (Line.startswith("// ")) // comment. + continue; + Lines.insert(Line); + } + return 0; +} + +static bool readBreakageAllowlist(SDKContext &Ctx, llvm::StringSet<> &lines) { + if (options::BreakageAllowlistPath.empty()) + return 0; + CompilerInstance instance; + CompilerInvocation invok; + invok.setModuleName("ForClangImporter"); + if (instance.setup(invok)) + return 1; + ClangImporterOptions impOpts; + auto importer = ClangImporter::create(instance.getASTContext(), impOpts); + SmallString<128> preprocessedFilePath; + if (auto error = llvm::sys::fs::createTemporaryFile( + "breakage-allowlist-", "txt", preprocessedFilePath)) { + return 1; + } + if (importer->runPreprocessor(options::BreakageAllowlistPath, + preprocessedFilePath.str())) { + return 1; + } + return readFileLineByLine(preprocessedFilePath, lines); +} + static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, SDKNodeRoot *RightModule, StringRef OutputPath, llvm::StringSet<> ProtocolReqAllowlist) { @@ -2337,9 +2386,14 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, OS = FileOS.get(); } bool FailOnError; - std::unique_ptr pConsumer = - createDiagConsumer(*OS, FailOnError); - + auto allowedBreakages = std::make_unique>(); + if (readBreakageAllowlist(Ctx, *allowedBreakages)) { + Ctx.getDiags().diagnose(SourceLoc(), diag::cannot_read_allowlist, + options::BreakageAllowlistPath); + } + auto pConsumer = std::make_unique( + createDiagConsumer(*OS, FailOnError), std::move(allowedBreakages)); + SWIFT_DEFER { pConsumer->finishProcessing(); }; Ctx.addDiagConsumer(*pConsumer); Ctx.setCommonVersion(std::min(LeftModule->getJsonFormatVersion(), RightModule->getJsonFormatVersion())); @@ -2352,7 +2406,7 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, // Find member hoist changes to help refine diagnostics. findTypeMemberDiffs(LeftModule, RightModule, Ctx.getTypeMemberDiffs()); DiagnosisEmitter::diagnosis(LeftModule, RightModule, Ctx); - return FailOnError && Ctx.getDiags().hadAnyError() ? 1 : 0; + return FailOnError && pConsumer->hasError() ? 1 : 0; } static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, @@ -2493,28 +2547,6 @@ static int generateMigrationScript(StringRef LeftPath, StringRef RightPath, return 0; } -static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) { - auto FileBufOrErr = llvm::MemoryBuffer::getFile(Path); - if (!FileBufOrErr) { - llvm::errs() << "error opening file '" << Path << "': " - << FileBufOrErr.getError().message() << '\n'; - return 1; - } - - StringRef BufferText = FileBufOrErr.get()->getBuffer(); - while (!BufferText.empty()) { - StringRef Line; - std::tie(Line, BufferText) = BufferText.split('\n'); - Line = Line.trim(); - if (Line.empty()) - continue; - if (Line.startswith("// ")) // comment. - continue; - Lines.insert(Line); - } - return 0; -} - // This function isn't referenced outside its translation unit, but it // can't use the "static" keyword because its address is used for // getMainExecutable (since some platforms don't support taking the From af4199e4f6b0e97f700ef363f0d2c6e4d6a2b264 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 25 Aug 2020 16:56:18 -0700 Subject: [PATCH 468/663] [build-toolchain] Add an option to control if code built by the toolchain links by default to the OS runtime or the toolchain runtime. Today by default, we always link against the runtime runtime. This option just lets our users decide what they want, but leaves the defaults alone. --- utils/build-presets.ini | 33 +++++++++++++++++++++++++++++++++ utils/build-script-impl | 8 +++++++- utils/build-toolchain | 14 ++++++++++++-- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index b1fe751b1ac4f..6cfa2e6b749dc 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1277,6 +1277,7 @@ darwin-toolchain-display-name-short=%(darwin_toolchain_display_name_short)s darwin-toolchain-name=%(darwin_toolchain_xctoolchain_name)s darwin-toolchain-version=%(darwin_toolchain_version)s darwin-toolchain-alias=%(darwin_toolchain_alias)s +darwin-toolchain-require-use-os-runtime=0 [preset: mixin_osx_package_test] build-subdir=buildbot_osx @@ -1296,6 +1297,8 @@ lldb-test-swift-only # Path to the .tar.gz package we would create. installable-package=%(installable_package)s +[preset: mixin_osx_package,use_os_runtime]: +darwin-toolchain-require-use-os-runtime=1 [preset: buildbot_osx_package] mixin-preset= @@ -1306,6 +1309,11 @@ mixin-preset= # SKIP LLDB TESTS (67923799) skip-test-lldb +[preset: buildbot_osx_package,use_os_runtime] +mixin-preset= + buildbot_osx_package + mixin_osx_package,use_os_runtime + [preset: buildbot_osx_package,no_assertions] mixin-preset= mixin_osx_package_base @@ -1315,12 +1323,20 @@ dash-dash no-assertions +[preset: buildbot_osx_package,no_assertions,use_os_runtime] +mixin-preset= + buildbot_osx_package,no_assertions + mixin_osx_package,use_os_runtime [preset: buildbot_osx_package,no_assertions,lto] mixin-preset=buildbot_osx_package,no_assertions lto +[preset: buildbot_osx_package,no_assertions,lto,use_os_runtime] +mixin-preset= + buildbot_osx_package,no_assertions,lto + mixin_osx_package,use_os_runtime [preset: buildbot_osx_package,no_assertions,no_test] mixin-preset= @@ -1339,6 +1355,10 @@ skip-test-swiftsyntax skip-test-skstresstester skip-test-swiftevolve +[preset: buildbot_osx_package,no_assertions,no_test,use_os_runtime] +mixin-preset= + buildbot_osx_package,no_assertions,no_test + mixin_osx_package,use_os_runtime # Debug version of the compilers, release version of the stdlib. [preset: buildbot_osx_package,tools=DA,stdlib=R] @@ -1352,6 +1372,11 @@ debug-llvm debug-swift no-swift-stdlib-assertions +[preset: buildbot_osx_package,tools=DA,stdlib=R,use_os_runtime] +mixin-preset= + buildbot_osx_package,tools=DA,stdlib=R + mixin_osx_package,use_os_runtime + [preset: mixin_buildbot_osx_package,no_test] skip-test-swift skip-test-swiftpm @@ -1370,6 +1395,14 @@ mixin-preset= buildbot_osx_package mixin_buildbot_osx_package,no_test +# macOS package without test that when linked against uses the OS runtime +# instead of the toolchain runtime. +[preset: buildbot_osx_package,no_test,use_os_runtime] +mixin-preset= + buildbot_osx_package + mixin_buildbot_osx_package,no_test + mixin_osx_package,use_os_runtime + #===------------------------------------------------------------------------===# # LLDB build configurations # diff --git a/utils/build-script-impl b/utils/build-script-impl index 4c4d499371b9a..ff67887c57fb0 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -114,6 +114,7 @@ KNOWN_SETTINGS=( darwin-toolchain-installer-package "" "The path to installer pkg" darwin-toolchain-name "" "Directory name for xctoolchain" darwin-toolchain-version "" "Version for xctoolchain info plist and installer pkg" + darwin-toolchain-require-use-os-runtime "0" "When setting up a plist for a toolchain, require the users of the toolchain to link against the OS instead of the packaged toolchain runtime. 0 for false, 1 for true" darwin-xcrun-toolchain "default" "the name of the toolchain to use on Darwin" ## Build Types for Components @@ -3050,6 +3051,11 @@ function build_and_test_installable_package() { COMPATIBILITY_VERSION_DISPLAY_STRING="Xcode 8.0" DARWIN_TOOLCHAIN_CREATED_DATE="$(date -u +'%a %b %d %T GMT %Y')" + SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME="YES" + if [[ "${DARWIN_TOOLCHAIN_REQUIRE_USE_OS_RUNTIME}" -eq "1" ]]; then + SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME="NO" + fi + echo "-- Removing: ${DARWIN_TOOLCHAIN_INFO_PLIST}" call rm -f ${DARWIN_TOOLCHAIN_INFO_PLIST} @@ -3068,7 +3074,7 @@ function build_and_test_installable_package() { call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_DISABLE_REQUIRED_ARCLITE string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_LINK_OBJC_RUNTIME string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_DEVELOPMENT_TOOLCHAIN string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" - call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" + call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME string '${SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}" call chmod a+r "${DARWIN_TOOLCHAIN_INFO_PLIST}" diff --git a/utils/build-toolchain b/utils/build-toolchain index 8188482a0eb6d..7768339ec1537 100755 --- a/utils/build-toolchain +++ b/utils/build-toolchain @@ -35,6 +35,9 @@ function usage() { echo "--preset-prefix" echo "Customize the preset invoked by prepending a prefix" echo "" + echo "--use-os-runtime" + echo "Require this toolchain to link against against the OS runtime rather than the toolchains packaged runtime" + echo "" } RESULT_DIR=$PWD @@ -46,6 +49,8 @@ DRY_RUN= BUNDLE_PREFIX= PRESET_FILE_FLAGS= PRESET_PREFIX= +PRESET_SUFFIX= + case $(uname -s) in Darwin) SWIFT_PACKAGE=buildbot_osx_package,no_test @@ -85,6 +90,9 @@ while [ $# -ne 0 ]; do --preset-prefix) shift PRESET_PREFIX="$1" + ;; + --use-os-runtime) + PRESET_SUFFIX=",use_os_runtime" ;; -h|--help) usage @@ -133,7 +141,8 @@ DRY_RUN="${DRY_RUN}" DISTCC_FLAG="${DISTCC_FLAG}" PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS}" -./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} ${PRESET_FILE_FLAGS} --preset="${PRESET_PREFIX}${SWIFT_PACKAGE}" \ +./utils/build-script ${DRY_RUN} ${DISTCC_FLAG} ${PRESET_FILE_FLAGS} \ + --preset="${PRESET_PREFIX}${SWIFT_PACKAGE}${PRESET_SUFFIX}" \ install_destdir="${SWIFT_INSTALL_DIR}" \ installable_package="${SWIFT_INSTALLABLE_PACKAGE}" \ install_toolchain_dir="${SWIFT_TOOLCHAIN_DIR}" \ @@ -144,4 +153,5 @@ PRESET_FILE_FLAGS="${PRESET_FILE_FLAGS}" darwin_toolchain_display_name_short="${DISPLAY_NAME_SHORT}" \ darwin_toolchain_xctoolchain_name="${TOOLCHAIN_NAME}" \ darwin_toolchain_version="${TOOLCHAIN_VERSION}" \ - darwin_toolchain_alias="Local" + darwin_toolchain_alias="Local" \ + darwin_toolchain_require_use_os_runtime="${REQUIRE_USE_OS_RUNTIME}" From 0b2b7b58e88b16c7d9c0a1d07c57959b270e3ddc Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 31 Aug 2020 11:18:27 -0700 Subject: [PATCH 469/663] [Constraint solver] Fix backward trailing closures with ".member" expressions The introduction of forward-scan matching for trailing closures (SE-0286) failed to account for unresolved member expressions, sometimes causing a crash in SILGen. Fixes rdar://problem/67781123. --- lib/Sema/CSApply.cpp | 4 +++- ...d_trailing_closure_unresolved_member.swift | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 test/expr/postfix/call/forward_trailing_closure_unresolved_member.swift diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 0add614158d91..640d7be2bcb82 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5592,7 +5592,9 @@ Expr *ExprRewriter::coerceCallArguments( SmallVector path; auto anchor = locator.getLocatorParts(path); if (!path.empty() && path.back().is() && - (anchor.isExpr(ExprKind::Call) || anchor.isExpr(ExprKind::Subscript))) { + (anchor.isExpr(ExprKind::Call) || + anchor.isExpr(ExprKind::Subscript) || + anchor.isExpr(ExprKind::UnresolvedMember))) { auto locatorPtr = cs.getConstraintLocator(locator); assert(solution.trailingClosureMatchingChoices.count(locatorPtr) == 1); trailingClosureMatching = solution.trailingClosureMatchingChoices.find( diff --git a/test/expr/postfix/call/forward_trailing_closure_unresolved_member.swift b/test/expr/postfix/call/forward_trailing_closure_unresolved_member.swift new file mode 100644 index 0000000000000..f65115051ddd6 --- /dev/null +++ b/test/expr/postfix/call/forward_trailing_closure_unresolved_member.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-emit-silgen %s | %FileCheck %s + +// rdar://problem/67781123 - crash in SILGen + +struct Foo { + var title: String + var handler1: ((Int, String) -> Void)? + var handler2: (() -> Void)? +} + +func take(foo: Foo) { } + +// CHECK-LABEL: sil hidden [ossa] @$s42forward_trailing_closure_unresolved_member4testyy +func test() { + // CHECK: function_ref @$s42forward_trailing_closure_unresolved_member4testyyFyycfU_ : $@convention(thin) () -> () + take(foo: .init(title: "") { + print("handler2 is called") + }) +} From c37d3c3917582c4420bab063a87aed6363a46444 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Mon, 31 Aug 2020 14:42:24 -0400 Subject: [PATCH 470/663] Update CHANGELOG.md table of contents, add SE-0287 (#33685) --- CHANGELOG.md | 77 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2af5d8f7abe..fc73f1d979750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,26 +4,68 @@ CHANGELOG