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-13951] RawRepresentable enum coercion to Optional source breaking change #56348

Closed
drodriguez opened this issue Dec 10, 2020 · 12 comments
Closed
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis

Comments

@drodriguez
Copy link
Collaborator

Previous ID SR-13951
Radar rdar://problem/72166791
Original Reporter @drodriguez
Type Bug
Status Closed
Resolution Done
Environment

Tested the following toolchains:

In macOS 10.15.7 x86_64.

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, TypeChecker
Assignee @drodriguez
Priority Medium

md5: 8e3daf6cf79749133ae0ebe4a5428509

Issue Description:

In recent toolchains (I tested https://swift.org/builds/development/xcode/swift-DEVELOPMENT-SNAPSHOT-2020-12-05-a/swift-DEVELOPMENT-SNAPSHOT-2020-12-05-a-osx.pkg and https://swift.org/builds/development/xcode/swift-DEVELOPMENT-SNAPSHOT-2020-11-13-a/swift-DEVELOPMENT-SNAPSHOT-2020-11-13-a-osx.pkg) a enum that is also RawRepresentable by a protocol doesn't seem to be coerced automatically into an Optional.

This works in Xcode 12.2.

The following code shows the problem:

public enum TheEnum: RawRepresentable {
   public typealias RawValue = TheProtocol

   case case1
   case case2

   public init?(rawValue: TheProtocol) {
    self = .case1
   }

   public var rawValue: TheProtocol {
    return TheType1()
   }
}

public protocol TheProtocol {}

public struct TheType1: TheProtocol {}

public func aTransformer(input: Int) -> TheEnum {
     if input % 2 == 0 {
         return .case1
     } else {
         return .case2
     }
 }

 public func theProblem(input: Int?) {
     var enumValue: TheEnum?
     if let input = input {
         // In Xcode 12.2 TheEnum is automatically coerced to TheEnum?
         // In recent toochains: Cannot assign value of type 'TheEnum' to type 'TheEnum?'
         enumValue = aTransformer(input: input)
     }

     _ = enumValue
 }

theProblem(input: nil)
theProblem(input: 0)
theProblem(input: 1)

If one removes the RawRepresentable conformance of the enum (the code that implements the conformance can stay), the problem goes away.

If one adds as TheEnum? at the end of the problematic line, the problem also goes away.

For some reason, the RawRepresentable and the coercion into Optional doesn't seem to work together.

@typesanitizer
Copy link

@swift-ci create

@LucianoPAlmeida
Copy link
Collaborator

This problem seems to be rooted on the fact that RawValue is a protocol type(as if you change it to e.g. String this type checks correctly), I didn't took a deep look at it just so still don't know the exact cause. Also, IgnoreAssignToDestination fix is being recorded on simplifyConformsToConstraint so a guess would be solver is trying to check a conformance where it doesn't have to ...

cc @xedin @hborla

@xedin
Copy link
Member

xedin commented Dec 12, 2020

@LucianoPAlmeida Looks like `repairFailures` is just too aggressive in this case and ends up trying to `repairByUsingRawValueOfRawRepresentableType` which is not what we want, instead we'd want to return let me go in the block that checks for presence of ValueToOptional conversion.

@xedin
Copy link
Member

xedin commented Dec 12, 2020

I have opened a PR to fix this situation - #35072

@xedin
Copy link
Member

xedin commented Dec 14, 2020

Fixed by #35072 @drodriguez Please use the next available snapshot of main branch to verify (12/15 or newer) and close this issue.

@drodriguez
Copy link
Collaborator Author

Thanks! I still haven't been able to double check the fix, since there haven't been a toolchain published since the 14th. I think the reason might be #35076 updating only one version of a test. Let's see if that can be fixed soon and I can test further.

@drodriguez
Copy link
Collaborator Author

I confirm that 2020-12-20 snapshot seems not to reproduce this bug. Thanks!

@drodriguez
Copy link
Collaborator Author

It seems that the fix might not be complete. I am reopening the issue, but tell me if you want me to open a new issue.

The following code shows the problem seems to still exist:

public enum TheEnum: RawRepresentable {
  public typealias RawValue = TheProtocol

  case case1
  case case2

  public init?(rawValue: TheProtocol) {
    self = .case1
  }

  public var rawValue: TheProtocol {
    return TheType1()
  }
}

public protocol TheProtocol {}

public struct TheType1: TheProtocol {}

public func theEnum(for input: Int) -> TheEnum {
  if input % 2 == 1 {
    return .case1
  } else {
    return .case2
  }
}

public func anotherProblem(input: Int?) -> TheType1 {
  var calculatedVariable: TheEnum? {
    if let anInput = input {
      // error: return expression of type 'TheEnum' does not conform to 'TheProtocol'
      return theEnum(for: anInput)
    } else {
      return nil
    }
  }

  // error: value of type 'TheEnum' does not conform to specified type 'TheProtocol'
  let directAssignment: TheEnum? = theEnum(for: input!)
}

@xedin
Copy link
Member

xedin commented Jan 7, 2021

Ah, looks like I got it fixed only for one situation. Going to get it updated and let you know, thank you!

@xedin
Copy link
Member

xedin commented Jan 7, 2021

Ok, I have landed #35291 which would address that problem. @drodriguez Please verify once the once snapshot is available.

@drodriguez
Copy link
Collaborator Author

I compiled the toolchain myself with that fix, and tried to compile the code that was failing for us, and seems that this second fix removes all the instances of the problem we were having. Thank you very much.

@xedin
Copy link
Member

xedin commented Jan 7, 2021

No worries! I'm going to cherry-pick this into 5.4 branch as well.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
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 type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

4 participants