pointfreeco / swift-parsing

A library for turning nebulous data into well-structured data, with a focus on composition, performance, generality, and ergonomics.
https://www.pointfree.co/collections/parsing
MIT License
864 stars 77 forks source link

Static method 'buildExpression' requires the types 'Substring.UTF8View' and 'Substring' be equivalent #294

Closed ilendemli closed 1 year ago

ilendemli commented 1 year ago

Hey! I have a compilation error with the Parser below. This parser worked before 0.12.0 with Xcode 13 and lazy var syntax instead of the new SwiftUI body syntax. I am not sure what the issue is here or what I have to change for this to work.

import Parsing

// example: `name="value" name2="value2"`
struct AttributesParser: Parser {
    typealias Output = Dictionary<String, String>

    var body: some Parser<Substring, Output> {
        Parse {
            Many {
                PrefixUpTo("=")
                    .map(.string)
                "="
                Parse {
                    "\""

                    PrefixUpTo("\"")
                        .map(.string)

                    "\""
                }
            } separator: {
                Whitespace(1..., .horizontal)
            }
        }
        .map { attributes in
            Dictionary(uniqueKeysWithValues: attributes)
        }
    }
}

// example: `a href="example.com" target="blank"`
struct TagContentParser: Parser {
    typealias Output = (String, [String: String])

    var body: some Parser<Substring, Output> {
        Parse {
            Prefix { character in
                character.isLetter
            }
            .map(.string)

            Optionally {
                Whitespace(1..., .horizontal)
                AttributesParser() // <- Error here
            }
            .map { attributes in
                attributes ?? [:]
            }

            Whitespace(.horizontal)
        }
    }
}
iampatbrown commented 1 year ago

Hey @ilendemli,

I'm not fully across the recent changes but using [String:String]() or .init() instead of [:] resolves the error for me.

You can also use .replaceError(with:) as an alternative to Optionally + .map(_:) if you're providing a default value.

Parse {
  Prefix(while: \.isLetter)
    .map(.string)

  Parse {
    Whitespace(1..., .horizontal)
    AttributesParser()
  }
  .replaceError(with: [String: String]())

  Whitespace(.horizontal)
}
ilendemli commented 1 year ago

@iampatbrown Interesting, this seems to be it. I noticed the type of attributes in my map is understandable [String: String] coming from AttributesParser.Output. So it makes sense to use [String: String](). But I would still have expected [:] to work here.

EDIT: This seems to work as well


.map { attributes -> [String: String] in
    attributes ?? [:]
}