swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.41k stars 10.34k forks source link

Type-inference failing for macro declaration (with `associatedtype` reference?) #63376

Open msteindorfer opened 1 year ago

msteindorfer commented 1 year ago

Description

Type checking the following macro declaration fails with the error message "Generic parameter 'T' could not be inferred":

@freestanding(expression) public macro regex<R: RegexComponent>(
  @RegexComponentBuilder _ body: () -> R
) -> Regex<R.RegexOutput> = #externalMacro(module: "MacroExamplesPlugin", type: "RegexMacro")

Note, that there is no generic type T mentioned in the signature, thus, the error might possibly originate from the #externalMacro or type-checking of the result thereof.

As an alternative I tried to remove the #externalMacro and go back to directly assigning the implementation:

@freestanding(expression) public macro regex<R: RegexComponent>(
  @RegexComponentBuilder _ body: () -> R
) -> Regex<R.RegexOutput> = MacroExamplesPlugin.RegexMacro

This leads to a compiler error:

  1. abbreviated:
(macro_decl "regex(_:)" <R : RegexComponent> interface type='(() -> R) -> <<error type>>' access=public)
  1. long form:
    
    checked decl cannot have error type
    (macro_decl range=[./swift-macro-examples/MacroExamplesLib/Macros.swift:31:34 - line:33:49] "regex(_:)" <R : RegexComponent> interface type='(() -> R) -> <<error type>>' access=public)
    Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
    Stack dump:
  2. Program arguments: [...]
  3. Apple Swift version 5.9-dev (LLVM dac17a9b87acc8e, Swift 3fd895a13da48fc)
  4. Compiling with the current language version Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var LLVM_SYMBOLIZER_PATH to point to it): 0 swift-frontend 0x0000000104e17a78 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56 1 swift-frontend 0x0000000104e16cfc llvm::sys::RunSignalHandlers() + 128 2 swift-frontend 0x0000000104e180b8 SignalHandler(int) + 304 3 libsystem_platform.dylib 0x00000001a86482a4 _sigtramp + 56 4 libsystem_pthread.dylib 0x00000001a8619cec pthread_kill + 288 5 libsystem_c.dylib 0x00000001a85522c8 abort + 180 6 swift-frontend 0x00000001052826d0 (anonymous namespace)::Verifier::verifyChecked(swift::VarDecl) (.cold.1) + 0 7 swift-frontend 0x00000001017398b0 (anonymous namespace)::Verifier::verifyChecked(swift::ValueDecl) + 284 8 swift-frontend 0x00000001017332b0 (anonymous namespace)::Verifier::walkToDeclPost(swift::Decl) + 4320 9 swift-frontend 0x000000010173b168 (anonymous namespace)::Traversal::doIt(swift::Decl) + 288 10 swift-frontend 0x000000010173b03c swift::Decl::walk(swift::ASTWalker&) + 32 11 swift-frontend 0x00000001018f902c swift::SourceFile::walk(swift::ASTWalker&) + 236 12 swift-frontend 0x0000000101728e00 swift::verify(swift::SourceFile&) + 96 13 swift-frontend 0x00000001019ff404 swift::TypeCheckSourceFileRequest::cacheResult(std::__1::tuple<>) const + 76 14 swift-frontend 0x0000000101544740 llvm::Expected swift::Evaluator::getResultCached<swift::TypeCheckSourceFileRequest, (void)0>(swift::TypeCheckSourceFileRequest const&) + 160 15 swift-frontend 0x0000000101542394 swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType) + 44 16 swift-frontend 0x00000001006721c8 bool llvm::function_ref<bool (swift::SourceFile&)>::callback_fn<swift::CompilerInstance::performSema()::$_7>(long, swift::SourceFile&) + 16 17 swift-frontend 0x000000010066de24 swift::CompilerInstance::forEachFileToTypeCheck(llvm::function_ref<bool (swift::SourceFile&)>) + 76 18 swift-frontend 0x000000010066ddb8 swift::CompilerInstance::performSema() + 76 19 swift-frontend 0x000000010051290c withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 60 20 swift-frontend 0x0000000100505814 swift::performFrontend(llvm::ArrayRef<char const>, char const, void, swift::FrontendObserver) + 3216 21 swift-frontend 0x000000010035c9a4 swift::mainEntry(int, char const**) + 3304 22 dyld

Steps to reproduce

  1. Use project https://github.com/DougGregor/swift-macro-examples
  2. Use swift-DEVELOPMENT-SNAPSHOT-2023-01-30-a-osx snapshot toolchain
  3. Either replicate the #regex type signature given earlier on, or transform on of the standard examples, like #stringify to use generics in a similar fashion, e.g.:
@freestanding(expression) public macro stringify<T: RegexComponent>(
  _ value: T
) -> (Regex<T.RegexOutput>, String) = #externalMacro(module: "MacroExamplesPlugin", type: "StringifyMacro")

Actually, even more simplified, just referencing the associated type T.RegexOutput makes the declaration already fail:

@freestanding(expression) public macro stringify<T: RegexComponent>(
  _ value: T
) -> (T.RegexOutput, String) = #externalMacro(module: "MacroExamplesPlugin", type: "StringifyMacro")

Expected behavior The #regex macro declaration is supposed to type-check, not cause Xcode warning, or Swift compiler errors.

Environment

msteindorfer commented 1 year ago

/cc @rxwei @DougGregor

rxwei commented 1 year ago

Minimal repro (but without the crash):

/Users/rxwei/Development/Swift/swift-source/swift/test/Macros/macros_diagnostics.swift:70:80: error: unexpected error produced: generic parameter 'T' could not be inferred
@freestanding(expression) macro usesAssocType<T: BinaryInteger>: T.Magnitude = #externalMacro(module: "MissingModule", type: "MissingType")

Basically, anything that has an associated type at the return position triggers it.