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-14142] Emitted swiftinterface file can have Swift errors, breaks module compatibility #56521

Closed
lilyball mannequin opened this issue Feb 2, 2021 · 5 comments
Closed
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@lilyball
Copy link
Mannequin

lilyball mannequin commented Feb 2, 2021

Previous ID SR-14142
Radar rdar://problem/73985891
Original Reporter @lilyball
Type Bug
Status Closed
Resolution Duplicate

Attachment: Download

Environment

Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Target: x86_64-apple-darwin19.6.0

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

md5: e6ce75a2f862cf8a7de2456e78cc9b44

Issue Description:

I've found two ways in which the emitted .swiftinterface file can contain Swift errors, breaking module compatibility. This can break binary Swift frameworks across Xcode updates. This was really confusing to us for the past 6 months but it seems Swift only uses this file when compiling with a different compiler.

The first issue is if the module contains a type with the same name, the swiftinterface file breaks completely. This file qualifies every referenced type name from the current module with the module name as well, but because the name conflicts with a type from the file, the compiler interprets these paths as relative to the type, not the module, and fails to look up all of the referenced types. I suspect this can happen when referring to types from an imported module that has the same setup, but I haven't tried that specific scenario. (Tracked by SR-898.)

The other example is more insidious. It turns out that you can write Swift code where an associatedtype is inferred and it compiles just fine, but writing out the explicit typealias instead of inferring it causes behavior to change. In particular, the following code triggers this behavior:

public struct ReplaySubject: SubjectType {
    public typealias SubjectObserverType = ReplaySubject
    // The following gets inferred by the compiler:
    //     public typealias Observer = ReplaySubject.SubjectObserverType
    // It works as long as it's inferred, but when made explicit in the
    // .swiftinterface it breaks.
    public func asObserver() -> SubjectObserverType {
        fatalError()
    }
}

public protocol SubjectType {
    associatedtype Observer
    @available(*, deprecated)
    typealias SubjectObserverType = Self.Observer
    func asObserver() -> Self.Observer
}

With the typealias written out explicitly, this code will complain "type alias 'Observer' references itself". It seems that it ends up evaluating the reference to ReplaySubject.SubjectObserverType using the typealias from SubjectType instead of the typealias from ReplaySubject. But this only happens when the reference is qualified, writing this as typealias Observer = SubjectObserverType compiles just fine.

The typealias thing here definitely seems like a bug in general, but this particular ticket is concerned with the fact that the generated .swiftinterface can trigger it when the original source didn't.

I've attached a zipped SPM project that can be used to reproduce this.

1. Run swift build. This should produce two .swiftinterface files in the project root.
2. Copy the contents of those generated files back into SameName.swift and TypeAlias.swift.
3. Run swift build again.

The second swift build will produce the above errors.


The generated swiftinterface files for reference:

// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
// swift-module-flags: -target x86_64-apple-macosx10.10 -enable-objc-interop -enable-library-evolution -swift-version 5 -Onone -module-name SameName
import Swift
public struct SameName {
}
public struct SomethingElse {
  public typealias Foo = SameName.Bar
}
public struct Bar {
}
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
// swift-module-flags: -target x86_64-apple-macosx10.10 -enable-objc-interop -enable-library-evolution -swift-version 5 -Onone -module-name TypeAlias
import Swift
public struct ReplaySubject : TypeAlias.SubjectType {
  public typealias SubjectObserverType = TypeAlias.ReplaySubject
  public typealias Observer = TypeAlias.ReplaySubject.SubjectObserverType
  public func asObserver() -> TypeAlias.ReplaySubject.SubjectObserverType
}
public protocol SubjectType {
  associatedtype Observer
  @available(*, deprecated)
  typealias SubjectObserverType = Self.Observer
  func asObserver() -> Self.Observer
}
@beccadax
Copy link
Contributor

beccadax commented Feb 2, 2021

The first issue (or rather, the missing underlying language feature) is already tracked by SR-898, so let's use this bug for the second issue.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Feb 3, 2021

Fixing SR-898 would certainly be the best way to resolve the first issue, though it doesn't explicitly cover the case where source can compile just fine but the generated swiftinterface file then hits that problem. A temporary workaround would be to stop qualifying symbols with the module in the swiftinterface if doing so would trigger this.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Feb 3, 2021

As a workaround it was suggested to pass -Xfrontend -module-interface-preserve-types-as-written while using whole-module optimization. This mostly works around the name collision issue, but see SR-14153 for a case where it doesn't.

@typesanitizer
Copy link

typesanitizer commented Feb 4, 2021

@swift-ci create

@artemcm
Copy link
Contributor

artemcm commented Feb 11, 2021

@lilyball, this issue no-longer reproduces when using a recent compiler (a development snapshot or a 5.4 toolchain), so it looks like it has already been fixed.

When I am trying to verify with a 5.4 toolchain,

swift -frontend -compile-module-from-interface TypeAlias.swiftinterface -sdk <SDK_PATH>

Runs without errors.

@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
Projects
None yet
Development

No branches or pull requests

3 participants