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

[SR-2145] Incorrect fix-it application when correcting optionals as booleans in a ternary in a lazy-var initializer #44753

Open
swift-ci opened this issue Jul 21, 2016 · 3 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself diagnostics QoI Bug: Diagnostics Quality of Implementation good first issue Good for newcomers

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-2145
Radar None
Original Reporter fbartho (JIRA User)
Type Bug
Environment
  • Xcode: Version 8.0 beta 3 (8S174q)

  • Commandline tools: Xcode 8.0 (8S174q)

  • macOS: 10.11.6 (15G31)

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, DiagnosticsQoI, StarterBug
Assignee None
Priority Medium

md5: c713c996341946e49c76cdb770caa2f1

Issue Description:

1. Write a simple class that has optional member vars.
2. Add a lazy var, and prepare an initializer for a lazy member variable.
Example:

class Original {
    var opt1: String? = nil
    var opt2: String? = nil
    enum Foo : String {
        case unknown
        case one
        case two
    }
    lazy var type: Foo = {
        return self.opt1 ? .one
            : self.opt2 ? .two
            : .unknown
    }()
}

3. Notice that there's a compile error with a fix-it on the return line suggesting to test for != nil instead
4. Click the fix-it to apply the suggested correction:
This produces the following output:

    lazy var type: Foo = ({
        return self.opt1 ? .one
            : self.opt2 ? .two
            : .unknown
        }() != nil) /// Now a compiler error highlighting this line

Expected Result:

    lazy var type: Foo = {
        return (nil != self.opt1) ? .one
            : (nil != self.opt2) ? .two
            : .unknown
    }()

Reproduces in an iOS project & in a playground

@belkadan
Copy link
Contributor

Most likely the != nil fix-it is applying to the top-level expression in a constraint system rather than the one that was inferred Optional. If that's true, the challenge is probably tracking this down rather than the actual fix, so I'm going to flag it as a Starter Bug.

@ChristopherRogers
Copy link
Contributor

I couldn't reproduce this in Xcode 8.2.1. Looks like someone fixed it.

@haikusw
Copy link
Contributor

haikusw commented Nov 16, 2018

Xcode 10.1 / Swift 4.2.1 - tested in a playground.

Using the test code above I had to fix two other compiler errors before I could try to reproduce this bug. Specifically, references to Foo's enum cases .one, .two and .unknown produce the following type of error:

error: tests.playground:21:23: error: reference to member 'one' cannot be resolved without a contextual type

            return self.opt1 ? .one

No fix-it offered. Fixing those manually produces Xcode 10.1 / Swift 4.2.1 compatible test code:

class Original {
    var opt1: String? = nil
    var opt2: String? = nil
    enum Foo : String {
        case unknown
        case one
        case two
    }

    lazy var type: Foo = {
        return self.opt1 ? Foo.one
            : self.opt2 ? Foo.two
            : Foo.unknown
    }()
}

At which point I get the error indicated in this bug:

error: tests.playground:22:11: error: optional type 'String?' cannot be used as a boolean; test for '!= nil' instead
: self.opt2 ? Foo.two
^
( != nil)

and electing to fix it (twice, once for opt1 and one for opt2) produces the correct fix(es):

class Original {
    var opt1: String? = nil
    var opt2: String? = nil
    enum Foo : String {
        case unknown
        case one
        case two
    }

    lazy var type: Foo = {
        return (self.opt1 != nil) ? Foo.one
            : (self.opt2 != nil) ? Foo.two
            : Foo.unknown
    }()
}

So seems like this bug can be closed.

However, there is another bug revealed, perhaps: those contextual type errors go away once you fix the != nil issues. By which I mean, removing the Foo type prefix from .one etc as follows:

class Original {
    var opt1: String? = nil
    var opt2: String? = nil
    enum Foo : String {
        case unknown
        case one
        case two
    }

    lazy var type: Foo = {
        return (self.opt1 != nil) ? .one
            : (self.opt2 != nil) ? .two
            : .unknown
    }()
}

produces code considered valid by the compiler with no errors emitted.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself diagnostics QoI Bug: Diagnostics Quality of Implementation good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

4 participants