Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A limit for Swift compiler? #50

Closed
lolgear opened this issue Jan 25, 2020 · 10 comments
Closed

A limit for Swift compiler? #50

lolgear opened this issue Jan 25, 2020 · 10 comments

Comments

@lolgear
Copy link

lolgear commented Jan 25, 2020

I am using currying for options in Commandant library.

Following code will not compile and aborted with type inference error.

struct Options: OptionsProtocol {
    fileprivate let filePath: String
    fileprivate let debug: Bool
    fileprivate let outputFilePath: String
    fileprivate let transform: String
    fileprivate let list: Bool
    fileprivate let templateFilePath: String
    fileprivate let commentsHeaderPath: String
    fileprivate let moduleFilePath: String
    
    public static func create() -> (String) -> (Bool) -> (String) -> (String) -> (Bool) -> (String) -> (String) -> (String) -> Self {
        return  { a in
                { b in
                { c in
                { d in
                { e in
                { f in
                { g in
                { h in
                    Options.init(filePath: a, debug: b, outputFilePath: c, transform: d, list: e, templateFilePath: f, commentsHeaderPath: g, moduleFilePath: h)
            }}}}}}}}
    }
    
    public static func evaluate(_ m: CommandMode) -> Result<Self, CommandantError<Swift.Error>> {
        return curry(Self.init)
            <*> m <| Option(key: "filePath", defaultValue: "", usage: "The path to the file in 'generate' action.")
            <*> m <| Switch(flag: "d", key: "debug", usage: "DEBUG")
            <*> m <| Option(key: "outputFilePath", defaultValue: "", usage: "Use with flag --filePath. It will output to this file")
            <*> m <| Option(key: "transform", defaultValue: "", usage: "Transform with name or shortcut.")
            <*> m <| Switch(flag: "l", key: "list", usage: "List available transforms")
            <*> m <| Option(key: "templateFilePath", defaultValue: "", usage: "Template file that should be used in some transforms")
            <*> m <| Option(key: "commentsHeaderPath", defaultValue: "", usage: "Comments header file that will be included at top")
            <*> m <| Option(key: "moduleFilePath", defaultValue: "", usage: "Module file that will be included at top after comments if presented")
    }
}

UPD:
Error while compiling ( with Internal error in Source code editor when it prays to file a bug. )

<unknown>:0: error: fatal error encountered during compilation; please file a bug report with your project and the crash log
<unknown>:0: note: Type variable id overflow
@gfontenot
Copy link
Collaborator

Can you give me more information about the error you're seeing? We definitely have a limit on the number of arguments we can write curry for, but we're currently shipping implementations out to 20 arguments, so you shouldn't be hitting that.

Side note: Unless create is required by OptionsProtocol, you don't need to write it. That was only required in really early Swift versions because we couldn't pass init around as a function. That being said, I'd be interested to know if you see the same error when you replace curry(Self.init) with Self.create.

@lolgear
Copy link
Author

lolgear commented Jan 26, 2020

@gfontenot
Error occurs only in curry(Self.init).

Error

<unknown>:0: error: fatal error encountered during compilation; please file a bug report with your project and the crash log
<unknown>:0: note: Type variable id overflow

@gfontenot
Copy link
Collaborator

Searching for that note ("Type variable id overflow") leads me to this issue in Carthage (which uses both Commandant and Curry): Carthage/Carthage#2831. It looks like it has something to do with the defaultValue argument. I have absolutely no idea why it would only happen when using curry, but a workaround is outlined in the Carthage issue. Does that work for you?

@lolgear
Copy link
Author

lolgear commented Jan 27, 2020

@gfontenot Hah, yes, it works.

fileprivate static let defaultStringValue: String = ""

        public static func evaluate(_ m: CommandMode) -> Result<Self, CommandantError<Swift.Error>> {
            return curry(Self.init)
                <*> m <| Option(key: "filePath", defaultValue: defaultStringValue, usage: "The path to the file in 'generate' action.")
                <*> m <| Switch(flag: "d", key: "debug", usage: "DEBUG")
                <*> m <| Option(key: "outputFilePath", defaultValue: defaultStringValue, usage: "Use with flag --filePath. It will output to this file")
                <*> m <| Option(key: "transform", defaultValue: "", usage: "Transform with name or shortcut.")
                <*> m <| Switch(flag: "l", key: "list", usage: "List available transforms")
                <*> m <| Option(key: "templateFilePath", defaultValue: defaultStringValue, usage: "Template file that should be used in some transforms")
                <*> m <| Option(key: "commentsHeaderFilePath", defaultValue: defaultStringValue, usage: "Comments header file that will be included at top")
                <*> m <| Option(key: "importsFilePath", defaultValue: defaultStringValue, usage: "Import file that will be included at top after comments if presented")
        }

@lolgear
Copy link
Author

lolgear commented Jan 27, 2020

Interesting, that for 7 options it works fine, but for 8 and more it doesn't work without this hack.

@gfontenot
Copy link
Collaborator

Yeah, very weird. No idea what the compiler is doing. Worth noting that there'a ticket opened against Swift to track the issue.

@lolgear
Copy link
Author

lolgear commented Jan 27, 2020

@gfontenot Could you add workaround to Readme?

@gfontenot
Copy link
Collaborator

I'm actually not sure if this is a workaround for Commandant or for Curry. Maybe @ikesyo has thoughts on this?

@ikesyo
Copy link
Contributor

ikesyo commented Jan 29, 2020

I think there are so many type inferences regarding the usages of <*> and <| operators, those are hitting compiler limit. I assume that you don't need a variable fileprivate static let defaultStringValue: String = ""; instead you can annotate each Option e.g. Option<String>(key: "filePath", defaultValue: "", usage: ...).

@gfontenot
Copy link
Collaborator

Ah yeah that makes sense too. I didn't know the full type of Option.

If this is going to be called out somewhere, I do think it should probably be in Commandant, since it's not actually specific to Curry, but is instead an issue when using Commandant with Curry.

I'm going to go ahead and close this issue for now, but please let me know if I can help further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants