From 2410da42597f4a565cc1edee1e02befd58d4a6a9 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 7 Jun 2023 19:04:23 +0000 Subject: [PATCH 1/9] [static-stdlib] Move static-executable-args.lnk under stdlib/public/Resources/linux This is a preparatory change for adding a static executable support for WASI --- .../public/Resources/linux}/static-executable-args.lnk | 0 stdlib/public/runtime/CMakeLists.txt | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename {utils => stdlib/public/Resources/linux}/static-executable-args.lnk (100%) diff --git a/utils/static-executable-args.lnk b/stdlib/public/Resources/linux/static-executable-args.lnk similarity index 100% rename from utils/static-executable-args.lnk rename to stdlib/public/Resources/linux/static-executable-args.lnk diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 379f72b010a72..e544ebd16fe1e 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -105,18 +105,19 @@ set(sdk "${SWIFT_HOST_VARIANT_SDK}") if(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "LINUX") set(static_binary_lnk_file_list) string(TOLOWER "${sdk}" lowercase_sdk) + set(static_binary_lnk_src "${SWIFT_SOURCE_DIR}/stdlib/public/Resources/${lowercase_sdk}/static-executable-args.lnk") # Generate the static-executable-args.lnk file used for ELF systems (eg linux) set(linkfile "${lowercase_sdk}/static-executable-args.lnk") add_custom_command_target(swift_static_binary_${sdk}_args COMMAND "${CMAKE_COMMAND}" -E copy - "${SWIFT_SOURCE_DIR}/utils/static-executable-args.lnk" + "${static_binary_lnk_src}" "${SWIFTSTATICLIB_DIR}/${linkfile}" OUTPUT "${SWIFTSTATICLIB_DIR}/${linkfile}" DEPENDS - "${SWIFT_SOURCE_DIR}/utils/static-executable-args.lnk") + "${static_binary_lnk_src}") list(APPEND static_binary_lnk_file_list ${swift_static_binary_${sdk}_args}) swift_install_in_component(FILES "${SWIFTSTATICLIB_DIR}/${linkfile}" From e228cd8b5fb50ad3fb8334445fdede34abcb72f6 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 10 Jun 2023 09:55:03 +0000 Subject: [PATCH 2/9] [wasm][build] Recognize wasi-wasm32 as valid host wasi-wasm32 support in build system was added in b1236e92f9c8f07620f4993486fbb872c9575954 but we forgot to add it to the host for the case when we are building the standalone stdlib for the target. --- CMakeLists.txt | 8 ++++++++ utils/build-script-impl | 1 + 2 files changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 563d40ee88540..54597829e7218 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1043,6 +1043,14 @@ elseif("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "ANDROID") set(SWIFT_PRIMARY_VARIANT_SDK_default "${SWIFT_HOST_VARIANT_SDK}") set(SWIFT_PRIMARY_VARIANT_ARCH_default "${SWIFT_HOST_VARIANT_ARCH}") +elseif("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "WASI") + set(SWIFT_HOST_VARIANT "wasi" CACHE STRING + "Deployment OS for Swift host tools (the compiler) [wasi]") + + configure_sdk_unix("WASI" "wasm32") + set(SWIFT_PRIMARY_VARIANT_SDK_default "${SWIFT_HOST_VARIANT_SDK}") + set(SWIFT_PRIMARY_VARIANT_ARCH_default "${SWIFT_HOST_VARIANT_ARCH}") + elseif("${SWIFT_HOST_VARIANT_SDK}" MATCHES "(OSX|IOS*|TVOS*|WATCHOS*)") set(SWIFT_HOST_VARIANT "macosx" CACHE STRING diff --git a/utils/build-script-impl b/utils/build-script-impl index f3941c1427948..457a7077905ae 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -481,6 +481,7 @@ function verify_host_is_supported() { | watchsimulator-arm64 \ | watchos-armv7k \ | watchos-arm64_32 \ + | wasi-wasm32 \ | android-armv7 \ | android-aarch64 \ | android-x86_64) From 97ac3985e2a3be4a8209cda29a8626d712ea2ebf Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 11 Jun 2023 12:16:07 +0000 Subject: [PATCH 3/9] [Concurrency] Fix signature mismatch of _startTaskOnMainActor The function is defined in Task.cpp with a void return type, but referenced in Task.swift with an pointer return type. --- stdlib/public/Concurrency/Task.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/Concurrency/Task.swift b/stdlib/public/Concurrency/Task.swift index 6988cbde7363a..33913b927945f 100644 --- a/stdlib/public/Concurrency/Task.swift +++ b/stdlib/public/Concurrency/Task.swift @@ -933,7 +933,7 @@ extension UnsafeCurrentTask: Equatable { func _getCurrentAsyncTask() -> Builtin.NativeObject? @_silgen_name("swift_task_startOnMainActor") -fileprivate func _startTaskOnMainActor(_ task: Builtin.NativeObject) -> Builtin.NativeObject? +fileprivate func _startTaskOnMainActor(_ task: Builtin.NativeObject) @available(SwiftStdlib 5.1, *) @_silgen_name("swift_task_getJobFlags") From 19f74e22e604c7584d5d715d22f63e2810b7742b Mon Sep 17 00:00:00 2001 From: Rauhul Varma Date: Mon, 22 May 2023 23:52:46 -0700 Subject: [PATCH 4/9] Add frontend flag for explicitly setting ccc Adds a new swift-frontend flag to allow users to choose which calling convention is used to make c function calls. This hidden flag is called `-experimental-platform-c-calling-convention`. This behavior is needed to workaround rdar://109431863 (Swift-frontend produces trapping llvm ir for non-trapping sil). The root cause of this issue is that IRGen always emits c function calls with llvm's default C calling convention. However clang may select a different (incompatible) calling convention for the function, eventually resulting--via InstCombine and SimplifyCFG--in a trap instead of the function call. This failure mode is most readily seen with the triple `armv7em-apple-none-macho` when attempting to call functions taking struct arguments. Example unoptimized ir below: ```llvm-ir call void @bar([4 x i32] %17, i32 2), !dbg !109 ... define internal arm_aapcs_vfpcc void @bar( [4 x i32] %bar.coerce, i32 noundef %x) ``` In the future it would be better to use the clang importer or some other tool to determine the calling convention for each function instead of setting the calling convention frontend invocation wide. Note: I don't know for sure whether or not clang should be explicitly annotating these functions with a calling convention instead of aliasing C to mean ARM_AAPCS_VFP for this particular combination of `-target`, `-mfloat-abi`, and `-mcpu`. --- include/swift/AST/IRGenOptions.h | 7 ++- include/swift/Option/FrontendOptions.td | 9 ++++ lib/Frontend/CompilerInvocation.cpp | 59 +++++++++++++++++++++++++ lib/IRGen/GenCall.cpp | 2 +- 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 67ce1590cbc82..f9927ab606438 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -25,6 +25,7 @@ #include "swift/Basic/OptimizationMode.h" #include "swift/Config.h" #include "clang/Basic/PointerAuthOptions.h" +#include "llvm/IR/CallingConv.h" // FIXME: This include is just for llvm::SanitizerCoverageOptions. We should // split the header upstream so we don't include so much. #include "llvm/Transforms/Instrumentation.h" @@ -477,6 +478,9 @@ class IRGenOptions { /// function instead of to trap instructions. std::string TrapFuncName = ""; + /// The calling convention used to perform non-swift calls. + llvm::CallingConv::ID ExperimentalPlatformCCallingConvention; + IRGenOptions() : DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssemblyAfterOptimization), @@ -517,7 +521,8 @@ class IRGenOptions { ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false), CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()), - TypeInfoFilter(TypeInfoDumpFilter::All) { + TypeInfoFilter(TypeInfoDumpFilter::All), + ExperimentalPlatformCCallingConvention(llvm::CallingConv::C) { #ifndef NDEBUG DisableRoundTripDebugTypes = false; #else diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 8e8ed8d5b46bb..3122c4c9724bb 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -1224,4 +1224,13 @@ def experimental_spi_only_imports : def enable_ossa_complete_lifetimes : Flag<["-"], "enable-ossa-complete-lifetimes">, HelpText<"Require linear OSSA lifetimes after SILGen">; + +def experimental_platform_c_calling_convention : + Separate<["-"], "experimental-platform-c-calling-convention">, + HelpText<"Which calling convention is used to perform non-swift calls. " + "Defaults to llvm's standard C calling convention.">, + MetaVarName<"standard|task-to-thread">; +def experimental_platform_c_calling_convention_EQ : + Joined<["-"], "experimental-platform-c-calling-convention=">, + Alias; } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7e4aa57a3c54b..e6d162cf11494 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2807,6 +2807,65 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, return true; } + if (const Arg *A = Args.getLastArg(options::OPT_experimental_platform_c_calling_convention)) { + Opts.ExperimentalPlatformCCallingConvention = + llvm::StringSwitch(A->getValue()) + .Case("c", llvm::CallingConv::C) + .Case("fast", llvm::CallingConv::Fast) + .Case("cold", llvm::CallingConv::Cold) + .Case("ghc", llvm::CallingConv::GHC) + .Case("hipe", llvm::CallingConv::HiPE) + .Case("webkit_js", llvm::CallingConv::WebKit_JS) + .Case("anyreg", llvm::CallingConv::AnyReg) + .Case("preservemost", llvm::CallingConv::PreserveMost) + .Case("preserveall", llvm::CallingConv::PreserveAll) + .Case("swift", llvm::CallingConv::Swift) + .Case("cxx_fast_tls", llvm::CallingConv::CXX_FAST_TLS) + .Case("tail", llvm::CallingConv::Tail) + .Case("cfguard_check", llvm::CallingConv::CFGuard_Check) + .Case("swifttail", llvm::CallingConv::SwiftTail) + .Case("firsttargetcc", llvm::CallingConv::FirstTargetCC) + .Case("x86_stdcall", llvm::CallingConv::X86_StdCall) + .Case("x86_fastcall", llvm::CallingConv::X86_FastCall) + .Case("arm_apcs", llvm::CallingConv::ARM_APCS) + .Case("arm_aapcs", llvm::CallingConv::ARM_AAPCS) + .Case("arm_aapcs_vfp", llvm::CallingConv::ARM_AAPCS_VFP) + .Case("msp430_intr", llvm::CallingConv::MSP430_INTR) + .Case("x86_thiscall", llvm::CallingConv::X86_ThisCall) + .Case("ptx_kernel", llvm::CallingConv::PTX_Kernel) + .Case("ptx_device", llvm::CallingConv::PTX_Device) + .Case("spir_func", llvm::CallingConv::SPIR_FUNC) + .Case("spir_kernel", llvm::CallingConv::SPIR_KERNEL) + .Case("intel_ocl_bi", llvm::CallingConv::Intel_OCL_BI) + .Case("x86_64_sysv", llvm::CallingConv::X86_64_SysV) + .Case("win64", llvm::CallingConv::Win64) + .Case("x86_vectorcall", llvm::CallingConv::X86_VectorCall) + .Case("x86_intr", llvm::CallingConv::X86_INTR) + .Case("avr_intr", llvm::CallingConv::AVR_INTR) + .Case("avr_signal", llvm::CallingConv::AVR_SIGNAL) + .Case("avr_builtin", llvm::CallingConv::AVR_BUILTIN) + .Case("amdgpu_vs", llvm::CallingConv::AMDGPU_VS) + .Case("amdgpu_gs", llvm::CallingConv::AMDGPU_GS) + .Case("amdgpu_ps", llvm::CallingConv::AMDGPU_PS) + .Case("amdgpu_cs", llvm::CallingConv::AMDGPU_CS) + .Case("amdgpu_kernel", llvm::CallingConv::AMDGPU_KERNEL) + .Case("x86_regcall", llvm::CallingConv::X86_RegCall) + .Case("amdgpu_hs", llvm::CallingConv::AMDGPU_HS) + .Case("msp430_builtin", llvm::CallingConv::MSP430_BUILTIN) + .Case("amdgpu_ls", llvm::CallingConv::AMDGPU_LS) + .Case("amdgpu_es", llvm::CallingConv::AMDGPU_ES) + .Case("aarch64_vectorcall", llvm::CallingConv::AArch64_VectorCall) + .Case("aarch64_sve_vectorcall", llvm::CallingConv::AArch64_SVE_VectorCall) + .Case("wasm_emscripteninvoke", llvm::CallingConv::WASM_EmscriptenInvoke) + .Case("amdgpu_gfx", llvm::CallingConv::AMDGPU_Gfx) + .Case("m68k_intr", llvm::CallingConv::M68k_INTR) + .Case("aarch64_sme_abi_support_routines_preservemost_from_x0", + llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0) + .Case("aarch64_sme_abi_support_routines_preservemost_from_x2", + llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2) + .Default(llvm::CallingConv::C); + } + return false; } diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 16fa1bc9e3a39..3c4414449c721 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -322,7 +322,7 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM, case SILFunctionTypeRepresentation::ObjCMethod: case SILFunctionTypeRepresentation::CXXMethod: case SILFunctionTypeRepresentation::Block: - return llvm::CallingConv::C; + return IGM.getOptions().ExperimentalPlatformCCallingConvention; case SILFunctionTypeRepresentation::Method: case SILFunctionTypeRepresentation::WitnessMethod: From 6b9fb171bfa9b556326e35f2a3707c2d9d330cc1 Mon Sep 17 00:00:00 2001 From: Rauhul Varma Date: Thu, 15 Jun 2023 22:06:43 -0700 Subject: [PATCH 5/9] Address rewview feedback - Renames ExperimentalPlatformCCallingConvention to PlatformCCallingConvention. - Removes non-arm calling convention support as this feature is working around a clang bug for some arm triples which we hope to see resolved. - Removes misleading MetaVarName from platform-c-calling-convention argument. - Replaces other uses of LLVM::CallingConv::C with IGM.getOptions().PlatformCCallingConvention(). --- include/swift/AST/IRGenOptions.h | 4 +- include/swift/Option/FrontendOptions.td | 9 ++--- lib/Frontend/CompilerInvocation.cpp | 53 +------------------------ lib/IRGen/GenCall.cpp | 2 +- lib/IRGen/GenDecl.cpp | 2 +- lib/IRGen/GenHeap.cpp | 2 +- lib/IRGen/IRGenModule.cpp | 2 +- 7 files changed, 12 insertions(+), 62 deletions(-) diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index f9927ab606438..ea81d878c0ced 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -479,7 +479,7 @@ class IRGenOptions { std::string TrapFuncName = ""; /// The calling convention used to perform non-swift calls. - llvm::CallingConv::ID ExperimentalPlatformCCallingConvention; + llvm::CallingConv::ID PlatformCCallingConvention; IRGenOptions() : DWARFVersion(2), @@ -522,7 +522,7 @@ class IRGenOptions { UseRelativeProtocolWitnessTables(false), CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()), TypeInfoFilter(TypeInfoDumpFilter::All), - ExperimentalPlatformCCallingConvention(llvm::CallingConv::C) { + PlatformCCallingConvention(llvm::CallingConv::C) { #ifndef NDEBUG DisableRoundTripDebugTypes = false; #else diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 3122c4c9724bb..b88be4acad09a 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -1225,12 +1225,11 @@ def enable_ossa_complete_lifetimes : Flag<["-"], "enable-ossa-complete-lifetimes">, HelpText<"Require linear OSSA lifetimes after SILGen">; -def experimental_platform_c_calling_convention : +def platform_c_calling_convention : Separate<["-"], "experimental-platform-c-calling-convention">, HelpText<"Which calling convention is used to perform non-swift calls. " - "Defaults to llvm's standard C calling convention.">, - MetaVarName<"standard|task-to-thread">; -def experimental_platform_c_calling_convention_EQ : + "Defaults to llvm's standard C calling convention.">; +def platform_c_calling_convention_EQ : Joined<["-"], "experimental-platform-c-calling-convention=">, - Alias; + Alias; } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index e6d162cf11494..c3182dffc347a 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2807,62 +2807,13 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, return true; } - if (const Arg *A = Args.getLastArg(options::OPT_experimental_platform_c_calling_convention)) { - Opts.ExperimentalPlatformCCallingConvention = + if (const Arg *A = Args.getLastArg(options::OPT_platform_c_calling_convention)) { + Opts.PlatformCCallingConvention = llvm::StringSwitch(A->getValue()) .Case("c", llvm::CallingConv::C) - .Case("fast", llvm::CallingConv::Fast) - .Case("cold", llvm::CallingConv::Cold) - .Case("ghc", llvm::CallingConv::GHC) - .Case("hipe", llvm::CallingConv::HiPE) - .Case("webkit_js", llvm::CallingConv::WebKit_JS) - .Case("anyreg", llvm::CallingConv::AnyReg) - .Case("preservemost", llvm::CallingConv::PreserveMost) - .Case("preserveall", llvm::CallingConv::PreserveAll) - .Case("swift", llvm::CallingConv::Swift) - .Case("cxx_fast_tls", llvm::CallingConv::CXX_FAST_TLS) - .Case("tail", llvm::CallingConv::Tail) - .Case("cfguard_check", llvm::CallingConv::CFGuard_Check) - .Case("swifttail", llvm::CallingConv::SwiftTail) - .Case("firsttargetcc", llvm::CallingConv::FirstTargetCC) - .Case("x86_stdcall", llvm::CallingConv::X86_StdCall) - .Case("x86_fastcall", llvm::CallingConv::X86_FastCall) .Case("arm_apcs", llvm::CallingConv::ARM_APCS) .Case("arm_aapcs", llvm::CallingConv::ARM_AAPCS) .Case("arm_aapcs_vfp", llvm::CallingConv::ARM_AAPCS_VFP) - .Case("msp430_intr", llvm::CallingConv::MSP430_INTR) - .Case("x86_thiscall", llvm::CallingConv::X86_ThisCall) - .Case("ptx_kernel", llvm::CallingConv::PTX_Kernel) - .Case("ptx_device", llvm::CallingConv::PTX_Device) - .Case("spir_func", llvm::CallingConv::SPIR_FUNC) - .Case("spir_kernel", llvm::CallingConv::SPIR_KERNEL) - .Case("intel_ocl_bi", llvm::CallingConv::Intel_OCL_BI) - .Case("x86_64_sysv", llvm::CallingConv::X86_64_SysV) - .Case("win64", llvm::CallingConv::Win64) - .Case("x86_vectorcall", llvm::CallingConv::X86_VectorCall) - .Case("x86_intr", llvm::CallingConv::X86_INTR) - .Case("avr_intr", llvm::CallingConv::AVR_INTR) - .Case("avr_signal", llvm::CallingConv::AVR_SIGNAL) - .Case("avr_builtin", llvm::CallingConv::AVR_BUILTIN) - .Case("amdgpu_vs", llvm::CallingConv::AMDGPU_VS) - .Case("amdgpu_gs", llvm::CallingConv::AMDGPU_GS) - .Case("amdgpu_ps", llvm::CallingConv::AMDGPU_PS) - .Case("amdgpu_cs", llvm::CallingConv::AMDGPU_CS) - .Case("amdgpu_kernel", llvm::CallingConv::AMDGPU_KERNEL) - .Case("x86_regcall", llvm::CallingConv::X86_RegCall) - .Case("amdgpu_hs", llvm::CallingConv::AMDGPU_HS) - .Case("msp430_builtin", llvm::CallingConv::MSP430_BUILTIN) - .Case("amdgpu_ls", llvm::CallingConv::AMDGPU_LS) - .Case("amdgpu_es", llvm::CallingConv::AMDGPU_ES) - .Case("aarch64_vectorcall", llvm::CallingConv::AArch64_VectorCall) - .Case("aarch64_sve_vectorcall", llvm::CallingConv::AArch64_SVE_VectorCall) - .Case("wasm_emscripteninvoke", llvm::CallingConv::WASM_EmscriptenInvoke) - .Case("amdgpu_gfx", llvm::CallingConv::AMDGPU_Gfx) - .Case("m68k_intr", llvm::CallingConv::M68k_INTR) - .Case("aarch64_sme_abi_support_routines_preservemost_from_x0", - llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0) - .Case("aarch64_sme_abi_support_routines_preservemost_from_x2", - llvm::CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2) .Default(llvm::CallingConv::C); } diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 3c4414449c721..508fd5f0d1b4e 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -322,7 +322,7 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM, case SILFunctionTypeRepresentation::ObjCMethod: case SILFunctionTypeRepresentation::CXXMethod: case SILFunctionTypeRepresentation::Block: - return IGM.getOptions().ExperimentalPlatformCCallingConvention; + return IGM.getOptions().PlatformCCallingConvention; case SILFunctionTypeRepresentation::Method: case SILFunctionTypeRepresentation::WitnessMethod: diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 711c5bd05e108..03a46dffe65eb 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3297,7 +3297,7 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded( llvm::Function *thunk = llvm::Function::Create( assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module); - thunk->setCallingConv(llvm::CallingConv::C); + thunk->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); llvm::AttrBuilder attrBuilder(IGM.getLLVMContext()); IGM.constructInitialFnAttributes(attrBuilder); diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index fd6b761dd9e2c..015e656ec08c0 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -1978,7 +1978,7 @@ emitHeapMetadataRefForUnknownHeapObject(IRGenFunction &IGF, auto metadata = IGF.Builder.CreateCall( IGF.IGM.getGetObjectClassFunctionPointer(), object); metadata->setName(object->getName() + ".Type"); - metadata->setCallingConv(llvm::CallingConv::C); + metadata->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); metadata->setDoesNotThrow(); metadata->addFnAttr(llvm::Attribute::ReadOnly); return metadata; diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 970a555997210..91a42dc51d3f2 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -570,7 +570,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen, InvariantNode = llvm::MDNode::get(getLLVMContext(), {}); DereferenceableID = getLLVMContext().getMDKindID("dereferenceable"); - C_CC = llvm::CallingConv::C; + C_CC = IGM.getOptions().PlatformCCallingConvention(); // TODO: use "tinycc" on platforms that support it DefaultCC = SWIFT_DEFAULT_LLVM_CC; SwiftCC = llvm::CallingConv::Swift; From cc0ea25664546198971a56e81a9e3df12c7fd925 Mon Sep 17 00:00:00 2001 From: Rauhul Varma Date: Thu, 15 Jun 2023 23:27:21 -0700 Subject: [PATCH 6/9] Fixup silly compilation errors --- lib/IRGen/GenDecl.cpp | 2 +- lib/IRGen/GenHeap.cpp | 2 +- lib/IRGen/IRGenModule.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 03a46dffe65eb..ed9c67dd2596a 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3297,7 +3297,7 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded( llvm::Function *thunk = llvm::Function::Create( assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module); - thunk->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); + thunk->setCallingConv(IGM.getOptions().PlatformCCallingConvention); llvm::AttrBuilder attrBuilder(IGM.getLLVMContext()); IGM.constructInitialFnAttributes(attrBuilder); diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index 015e656ec08c0..b9657b1955eab 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -1978,7 +1978,7 @@ emitHeapMetadataRefForUnknownHeapObject(IRGenFunction &IGF, auto metadata = IGF.Builder.CreateCall( IGF.IGM.getGetObjectClassFunctionPointer(), object); metadata->setName(object->getName() + ".Type"); - metadata->setCallingConv(IGM.getOptions().PlatformCCallingConvention()); + metadata->setCallingConv(IGF.IGM.getOptions().PlatformCCallingConvention); metadata->setDoesNotThrow(); metadata->addFnAttr(llvm::Attribute::ReadOnly); return metadata; diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 91a42dc51d3f2..1e01dfdcbb021 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -570,7 +570,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen, InvariantNode = llvm::MDNode::get(getLLVMContext(), {}); DereferenceableID = getLLVMContext().getMDKindID("dereferenceable"); - C_CC = IGM.getOptions().PlatformCCallingConvention(); + C_CC = getOptions().PlatformCCallingConvention; // TODO: use "tinycc" on platforms that support it DefaultCC = SWIFT_DEFAULT_LLVM_CC; SwiftCC = llvm::CallingConv::Swift; From 2ee646f47bb34197af2c983966cf2bbf3c89ea6f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 16 Jun 2023 09:28:00 -0700 Subject: [PATCH 7/9] [ConstraintSystem] NFC: Generalize `DefaultClosureType` constraint This constraint is useful in more places than closures because it gives a way to provide a "fallback type" without it having effect on inference. --- include/swift/Sema/Constraint.h | 10 ++--- include/swift/Sema/ConstraintSystem.h | 11 ++--- lib/Sema/CSBindings.cpp | 15 ++++--- lib/Sema/CSGen.cpp | 6 +-- lib/Sema/CSSimplify.cpp | 40 +++++++++---------- lib/Sema/Constraint.cpp | 12 +++--- lib/Sema/ConstraintSystem.cpp | 2 +- .../Sema/ConstraintSimplificationTests.cpp | 2 +- 8 files changed, 48 insertions(+), 50 deletions(-) diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index 54e780d2c7a0f..5e7b688d38662 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -186,14 +186,12 @@ enum class ConstraintKind : char { /// constraint. OneWayBindParam, /// If there is no contextual info e.g. `_ = { 42 }` default first type - /// to a second type (inferred closure type). This is effectively a - /// `Defaultable` constraint which a couple of differences: + /// to a second type. This is effectively a `Defaultable` constraint + /// which one significant difference: /// - /// - References inferred closure type and all of the outer parameters - /// referenced by closure body. /// - Handled specially by binding inference, specifically contributes /// to the bindings only if there are no contextual types available. - DefaultClosureType, + FallbackType, /// The first type represents a result of an unresolved member chain, /// and the second type is its base type. This constraint acts almost /// like `Equal` but also enforces following semantics: @@ -701,7 +699,7 @@ class Constraint final : public llvm::ilist_node, case ConstraintKind::OptionalObject: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PackElementOf: case ConstraintKind::SameShape: diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index ecb534937af80..2b83ee8eee5a5 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -4852,11 +4852,12 @@ class ConstraintSystem { TypeMatchOptions flags, ConstraintLocatorBuilder locator); - /// Attempt to simplify the given defaultable closure type constraint. - SolutionKind simplifyDefaultClosureTypeConstraint( - Type closureType, Type inferredType, - ArrayRef referencedOuterParameters, - TypeMatchOptions flags, ConstraintLocatorBuilder locator); + /// Attempt to simplify the given fallback type constraint. + SolutionKind + simplifyFallbackTypeConstraint(Type defaultableType, Type fallbackType, + ArrayRef referencedVars, + TypeMatchOptions flags, + ConstraintLocatorBuilder locator); /// Attempt to simplify a property wrapper constraint. SolutionKind simplifyPropertyWrapperConstraint(Type wrapperType, Type wrappedValueType, diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 2b628a59a27f0..f28dc7bbe85ce 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -452,7 +452,7 @@ void BindingSet::inferTransitiveBindings( // Infer transitive defaults. for (const auto &def : bindings.Defaults) { - if (def.getSecond()->getKind() == ConstraintKind::DefaultClosureType) + if (def.getSecond()->getKind() == ConstraintKind::FallbackType) continue; addDefault(def.second); @@ -1510,7 +1510,7 @@ void PotentialBindings::infer(Constraint *constraint) { } case ConstraintKind::Defaultable: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: // Do these in a separate pass. if (CS.getFixedTypeRecursive(constraint->getFirstType(), true) ->getAs() == TypeVar) { @@ -1634,7 +1634,7 @@ void PotentialBindings::retract(Constraint *constraint) { break; case ConstraintKind::Defaultable: - case ConstraintKind::DefaultClosureType: { + case ConstraintKind::FallbackType: { Defaults.erase(constraint); break; } @@ -2075,11 +2075,10 @@ bool TypeVarBindingProducer::computeNext() { if (NumTries == 0) { // Add defaultable constraints (if any). for (auto *constraint : DelayedDefaults) { - if (constraint->getKind() == ConstraintKind::DefaultClosureType) { - // If there are no other possible bindings for this closure - // let's default it to the type inferred from its parameters/body, - // otherwise we should only attempt contextual types as a - // top-level closure type. + if (constraint->getKind() == ConstraintKind::FallbackType) { + // If there are no other possible bindings for this variable + // let's default it to the fallback type, otherwise we should + // only attempt contextual types. if (!ExploredTypes.empty()) continue; } diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index e6d7e415a2807..fcd3a374e05ff 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2921,9 +2921,9 @@ namespace { SmallVector referencedVars{ collectVarRefs.varRefs.begin(), collectVarRefs.varRefs.end()}; - CS.addUnsolvedConstraint(Constraint::create( - CS, ConstraintKind::DefaultClosureType, closureType, inferredType, - locator, referencedVars)); + CS.addUnsolvedConstraint( + Constraint::create(CS, ConstraintKind::FallbackType, closureType, + inferredType, locator, referencedVars)); CS.setClosureType(closure, inferredType); return closureType; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 49b82b210e1b1..8299872ae8019 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2284,7 +2284,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2, case ConstraintKind::BridgingConversion: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PropertyWrapper: case ConstraintKind::SyntacticElement: @@ -2643,7 +2643,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1, case ConstraintKind::ValueWitness: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PropertyWrapper: case ConstraintKind::SyntacticElement: @@ -3161,7 +3161,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, case ConstraintKind::BridgingConversion: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PropertyWrapper: case ConstraintKind::SyntacticElement: @@ -6811,7 +6811,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case ConstraintKind::ValueWitness: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PropertyWrapper: case ConstraintKind::SyntacticElement: @@ -10989,18 +10989,18 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyDefaultableConstraint( return SolutionKind::Solved; } -ConstraintSystem::SolutionKind -ConstraintSystem::simplifyDefaultClosureTypeConstraint( - Type closureType, Type inferredType, - ArrayRef referencedOuterParameters, - TypeMatchOptions flags, ConstraintLocatorBuilder locator) { - closureType = getFixedTypeRecursive(closureType, flags, /*wantRValue=*/true); +ConstraintSystem::SolutionKind ConstraintSystem::simplifyFallbackTypeConstraint( + Type defaultableType, Type fallbackType, + ArrayRef referencedVars, TypeMatchOptions flags, + ConstraintLocatorBuilder locator) { + defaultableType = + getFixedTypeRecursive(defaultableType, flags, /*wantRValue=*/true); - if (closureType->isTypeVariableOrMember()) { + if (defaultableType->isTypeVariableOrMember()) { if (flags.contains(TMF_GenerateConstraints)) { addUnsolvedConstraint(Constraint::create( - *this, ConstraintKind::DefaultClosureType, closureType, inferredType, - getConstraintLocator(locator), referencedOuterParameters)); + *this, ConstraintKind::FallbackType, defaultableType, fallbackType, + getConstraintLocator(locator), referencedVars)); return SolutionKind::Solved; } @@ -15064,7 +15064,7 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first, case ConstraintKind::Conjunction: case ConstraintKind::KeyPath: case ConstraintKind::KeyPathApplication: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::SyntacticElement: llvm_unreachable("Use the correct addConstraint()"); } @@ -15596,12 +15596,12 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { /*flags*/ None, constraint.getLocator()); - case ConstraintKind::DefaultClosureType: - return simplifyDefaultClosureTypeConstraint(constraint.getFirstType(), - constraint.getSecondType(), - constraint.getTypeVariables(), - /*flags*/ None, - constraint.getLocator()); + case ConstraintKind::FallbackType: + return simplifyFallbackTypeConstraint(constraint.getFirstType(), + constraint.getSecondType(), + constraint.getTypeVariables(), + /*flags*/ None, + constraint.getLocator()); case ConstraintKind::PropertyWrapper: return simplifyPropertyWrapperConstraint(constraint.getFirstType(), diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index bd8991909634c..8630e128df625 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -99,7 +99,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, llvm_unreachable("Wrong constructor for member constraint"); case ConstraintKind::Defaultable: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: assert(!First.isNull()); assert(!Second.isNull()); break; @@ -164,7 +164,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third, case ConstraintKind::Conjunction: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PropertyWrapper: case ConstraintKind::SyntacticElement: @@ -314,7 +314,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const { case ConstraintKind::Defaultable: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PropertyWrapper: case ConstraintKind::BindTupleOfFunctionParams: @@ -469,8 +469,8 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm, case ConstraintKind::OpenedExistentialOf: Out << " opened archetype of "; break; case ConstraintKind::OneWayEqual: Out << " one-way bind to "; break; case ConstraintKind::OneWayBindParam: Out << " one-way bind param to "; break; - case ConstraintKind::DefaultClosureType: - Out << " closure can default to "; + case ConstraintKind::FallbackType: + Out << " can fallback to "; break; case ConstraintKind::UnresolvedMemberChainBase: Out << " unresolved member chain base "; @@ -740,7 +740,7 @@ gatherReferencedTypeVars(Constraint *constraint, case ConstraintKind::SelfObjectOfProtocol: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: + case ConstraintKind::FallbackType: case ConstraintKind::UnresolvedMemberChainBase: case ConstraintKind::PropertyWrapper: case ConstraintKind::BindTupleOfFunctionParams: diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 35e2e0736721f..ebf67fc95dd96 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -7394,7 +7394,7 @@ bool TypeVarBindingProducer::requiresOptionalAdjustment( PotentialBinding TypeVarBindingProducer::getDefaultBinding(Constraint *constraint) const { assert(constraint->getKind() == ConstraintKind::Defaultable || - constraint->getKind() == ConstraintKind::DefaultClosureType); + constraint->getKind() == ConstraintKind::FallbackType); auto type = constraint->getSecondType(); Binding binding{type, BindingKind::Exact, constraint}; diff --git a/unittests/Sema/ConstraintSimplificationTests.cpp b/unittests/Sema/ConstraintSimplificationTests.cpp index c8c3271cc815b..d596e5317fe1e 100644 --- a/unittests/Sema/ConstraintSimplificationTests.cpp +++ b/unittests/Sema/ConstraintSimplificationTests.cpp @@ -111,7 +111,7 @@ TEST_F(SemaTest, TestClosureInferenceFromOptionalContext) { auto *closureTy = cs.createTypeVariable(closureLoc, /*options=*/0); cs.addUnsolvedConstraint(Constraint::create( - cs, ConstraintKind::DefaultClosureType, closureTy, defaultTy, + cs, ConstraintKind::FallbackType, closureTy, defaultTy, cs.getConstraintLocator(closure), /*referencedVars=*/{})); auto contextualTy = From 83bb9c1f5acf45ecf7fd06272af2ac34ff857ec3 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 16 Jun 2023 09:31:23 -0700 Subject: [PATCH 8/9] [ConstraintSystem] Use fallback type constraint to default pack expansion Binding of pack expansion types is delayed until solving but use of `Defaultable` was preventing it from being considered early because that constraint impacts binding set ranking, switching to `FallbackType` constraint give us better semantics where pack expansion type variables are going to be bound as soon as they have a contextual type. Resolves: rdar://110819621 --- lib/Sema/ConstraintSystem.cpp | 2 +- .../pack-expansion-expressions.swift | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index ebf67fc95dd96..5f27c5b29ddd7 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1031,7 +1031,7 @@ Type ConstraintSystem::openPackExpansionType(PackExpansionType *expansion, // This constraint is important to make sure that pack expansion always // has a binding and connect pack expansion var to any type variables // that appear in pattern and shape types. - addUnsolvedConstraint(Constraint::create(*this, ConstraintKind::Defaultable, + addUnsolvedConstraint(Constraint::create(*this, ConstraintKind::FallbackType, expansionVar, openedPackExpansion, expansionLoc)); diff --git a/test/Constraints/pack-expansion-expressions.swift b/test/Constraints/pack-expansion-expressions.swift index 8c09b8e167ca5..bc58495e4944e 100644 --- a/test/Constraints/pack-expansion-expressions.swift +++ b/test/Constraints/pack-expansion-expressions.swift @@ -561,3 +561,45 @@ func configure( repeat item[keyPath: (each configuration).0] = (each configuration).1 return item } + +// rdar://110819621 - generic parameter is bound before pack expansion type which result in inference failures +func test_that_expansions_are_bound_early() { + struct Data { + let prop: Int? + } + + struct Value { + init(_ body: (repeat each T) -> Bool) {} + } + + func compute( + root: Root, + keyPath: KeyPath, + other: Value) -> Bool { true } + + func test_keypath(v: Int) { + let _: Value = Value({ + compute( + root: $0, + keyPath: \.prop, + other: v + ) + }) // Ok + + let _: Value = Value({ + compute( + root: $0, + keyPath: \.prop, + other: v + ) + }) // Ok + } + + func equal(_: Value, _: Value) -> Bool {} + + func test_equality(i: Int) { + let _: Value = Value({ + equal($0.prop, i) // Ok + }) + } +} From 6fffd96a18e96c5a991781b520af283bc8466c24 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 16 Jun 2023 21:37:47 +0100 Subject: [PATCH 9/9] [Parse] Avoid creating binding patterns in a couple more positions If we have an identifier followed by either `[` or a generic argument list, avoid turning it into a binding pattern, as that would be invalid. This is similar to the existing rule we have where a following `(` prevents a binding pattern from being formed. This allows patterns such as `let E.foo(x)` and `let (y[0], x)` to compile, where `x` is treated as a binding, but no other identifier is. rdar://108738034 --- lib/Parse/ParseExpr.cpp | 33 ++++++++++++++----- test/Constraints/rdar108738034.swift | 21 ++++++++++++ test/Parse/matching_patterns.swift | 48 ++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 test/Constraints/rdar108738034.swift diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 426c96b09c094..82a98eeb48867 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1664,19 +1664,35 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { } case tok::identifier: // foo - case tok::kw_self: // self - + case tok::kw_self: { // self + auto canParseBindingInPattern = [&]() { + if (InBindingPattern != PatternBindingState::ImplicitlyImmutable && + !InBindingPattern.getIntroducer().hasValue()) { + return false; + } + // If we have "case let x.", "case let x(", or "case let x[", we parse 'x' + // as a normal name, not a binding, because it is the start of an enum + // pattern, call, or subscript. + if (peekToken().isAny(tok::period, tok::period_prefix, tok::l_paren, + tok::l_square)) { + return false; + } + // If we have a generic argument list, this is something like + // "case let E.e(y)", and 'E' should be parsed as a normal name, not + // a binding. + if (peekToken().isAnyOperator() && peekToken().getText().equals("<")) { + BacktrackingScope S(*this); + consumeToken(); + return !canParseAsGenericArgumentList(); + } + return true; + }(); // If we are parsing a refutable pattern and are inside a let/var pattern, // the identifiers change to be value bindings instead of decl references. // Parse and return this as an UnresolvedPatternExpr around a binding. This // will be resolved (or rejected) by sema when the overall refutable pattern // it transformed from an expression into a pattern. - if ((InBindingPattern == PatternBindingState::ImplicitlyImmutable || - InBindingPattern.getIntroducer().hasValue()) && - // If we have "case let x." or "case let x(", we parse x as a normal - // name, not a binding, because it is the start of an enum pattern or - // call pattern. - peekToken().isNot(tok::period, tok::period_prefix, tok::l_paren)) { + if (canParseBindingInPattern) { Identifier name; SourceLoc loc = consumeIdentifier(name, /*diagnoseDollarPrefix=*/false); // If we have an inout/let/var, set that as our introducer. otherwise @@ -1710,6 +1726,7 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { } LLVM_FALLTHROUGH; + } case tok::kw_Self: // Self return parseExprIdentifier(); diff --git a/test/Constraints/rdar108738034.swift b/test/Constraints/rdar108738034.swift new file mode 100644 index 0000000000000..368eb480884b3 --- /dev/null +++ b/test/Constraints/rdar108738034.swift @@ -0,0 +1,21 @@ +// RUN: %target-typecheck-verify-swift + +// rdar://108738034: Make sure we can type-check this. +enum E: Error { + case e(T) +} + +struct S { + func bar(_: (Error?) -> Void) {} +} + +func foo(_ s: S) { + s.bar { error in + guard let error = error else { + return + } + if case let E.e(y) = error { + print(y) + } + } +} diff --git a/test/Parse/matching_patterns.swift b/test/Parse/matching_patterns.swift index 050916fac0574..2a78444f7719e 100644 --- a/test/Parse/matching_patterns.swift +++ b/test/Parse/matching_patterns.swift @@ -364,3 +364,51 @@ let (responseObject: Int?) = op1 // expected-error @-1 {{expected ',' separator}} {{25-25=,}} // expected-error @-2 {{expected pattern}} // expected-error @-3 {{cannot convert value of type 'Int?' to specified type '(responseObject: _)'}} + +enum E { + case e(T) +} + +// rdar://108738034 - Make sure we don't treat 'E' as a binding, but can treat +// 'y' as a binding +func testNonBinding1(_ x: E) -> Int { + if case let E.e(y) = x { y } else { 0 } +} + +func testNonBinding2(_ e: E) -> Int { + switch e { + case let E.e(y): + y + } +} + +// In this case, 'y' should be an identifier, but 'z' is a binding. +func testNonBinding3(_ x: (Int, Int), y: [Int]) -> Int { + if case let (y[0], z) = x { z } else { 0 } +} + +func testNonBinding4(_ x: (Int, Int), y: [Int]) -> Int { + switch x { + case let (y[0], z): + z + default: + 0 + } +} + +func testNonBinding5(_ x: Int, y: [Int]) { + // We treat 'z' here as a binding, which is invalid. + if case let y[z] = x {} // expected-error {{pattern variable binding cannot appear in an expression}} +} + +func testNonBinding6(y: [Int], z: Int) -> Int { + switch 0 { + // We treat 'z' here as a binding, which is invalid. + case let y[z]: // expected-error {{pattern variable binding cannot appear in an expression}} + z + case y[z]: // This is fine + 0 + default: + 0 + } +}