Files
swift-mirror/test/ModuleInterface/file_default_available.swift
Kyle 2edc61d3f1 [AST] Coalesce repeated availability domains when printing attributes (#93418)
## Motivation

Close #93415

## Summary

Separate `@available` attributes for the same platform are accepted in
source, but interface emission combines them into an invalid attribute
with duplicate platform entries.

Coalesce short-form availability attributes by domain, retaining the
greatest introduction version and preserving platform order. This
supports combining a shared availability macro such as `MyLib_v1_0` with
a stricter requirement on one platform.

## Test

Add regression coverage for the macro case in both attribute orders,
repeated versions, long and mixed forms, overlapping platform groups,
platform aliases, and preservation of deprecation information.
2026-10-22 14:11:55 +08:00

152 lines
6.1 KiB
Swift

// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// RUN: %target-swift-frontend -emit-module -module-name Legacy \
// RUN: -enable-library-evolution \
// RUN: -swift-version 5 \
// RUN: -o %t/Legacy.swiftmodule \
// RUN: -emit-module-interface-path %t/Legacy.swiftinterface \
// RUN: %t/legacy.swift
// RUN: %target-swift-typecheck-module-from-interface(%t/Legacy.swiftinterface) -module-name Legacy
// RUN: %FileCheck %t/legacy.swift --input-file %t/Legacy.swiftinterface
// RUN: %empty-directory(%t/top)
// RUN: %target-swift-frontend -emit-module -module-name Ordering \
// RUN: -enable-library-evolution \
// RUN: -swift-version 5 \
// RUN: -o %t/top/Ordering.swiftmodule \
// RUN: -emit-module-interface-path %t/top/Ordering.swiftinterface \
// RUN: -DTOP %t/ordering.swift
// RUN: %target-swift-typecheck-module-from-interface(%t/top/Ordering.swiftinterface) -module-name Ordering
// RUN: %FileCheck %t/ordering.swift --input-file %t/top/Ordering.swiftinterface
// RUN: %empty-directory(%t/bottom)
// RUN: %target-swift-frontend -emit-module -module-name Ordering \
// RUN: -enable-library-evolution \
// RUN: -swift-version 5 \
// RUN: -o %t/bottom/Ordering.swiftmodule \
// RUN: -emit-module-interface-path %t/bottom/Ordering.swiftinterface \
// RUN: -DBOTTOM %t/ordering.swift
// RUN: %target-swift-typecheck-module-from-interface(%t/bottom/Ordering.swiftinterface) -module-name Ordering
// RUN: %FileCheck %t/ordering.swift --input-file %t/bottom/Ordering.swiftinterface
// RUN: diff %t/top/Ordering.swiftinterface %t/bottom/Ordering.swiftinterface
// make sure filecheck fails with neither flag
// RUN: %empty-directory(%t/neither)
// RUN: %target-swift-frontend -emit-module -module-name Ordering \
// RUN: -enable-library-evolution \
// RUN: -swift-version 5 \
// RUN: -o %t/neither/Ordering.swiftmodule \
// RUN: -emit-module-interface-path %t/neither/Ordering.swiftinterface \
// RUN: %t/ordering.swift
// RUN: not %FileCheck %t/ordering.swift --input-file %t/neither/Ordering.swiftinterface
// RUN: %target-swift-frontend -typecheck -verify %t/consumer.swift -I %t -I %t/top
// RUN: %target-swift-frontend -typecheck -verify %t/consumer.swift -I %t -I %t/bottom
// RUN: %target-swift-emit-module-interface(%t/Introduced.swiftinterface) -module-name Introduced \
// RUN: -define-availability 'MyLib_v1_0:iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0' \
// RUN: %t/introduced.swift %t/stricter_default.swift
// RUN: %target-swift-typecheck-module-from-interface(%t/Introduced.swiftinterface) -module-name Introduced
// RUN: %FileCheck %s --check-prefix=INTRODUCED --input-file %t/Introduced.swiftinterface
//--- legacy.swift
// The `default` declaration itself must not appear in the emitted interface.
// CHECK-NOT: default @available
default @available(*, deprecated, message: "legacy module")
// CHECK: @available(*, deprecated, message: "legacy module")
// CHECK-NEXT: public func defaultedFunc()
public func defaultedFunc() {}
// CHECK: @available(*, deprecated, message: "legacy module")
// CHECK-NEXT: public class DefaultedClass
public class DefaultedClass {
// CHECK-NOT: @available
// CHECK: public init()
public init() {}
// CHECK-NOT: @available
// CHECK: public func method()
public func method() {}
}
// CHECK: @available(*, deprecated, message: "legacy module")
// CHECK-NEXT: extension Legacy::DefaultedClass
extension DefaultedClass {
public func extensionMethod() {}
}
// CHECK: @available(*, deprecated, message: "legacy module")
// CHECK-NEXT: @available(*, deprecated, message: "explicit")
// CHECK-NEXT: public func explicitlyDeprecated()
@available(*, deprecated, message: "explicit")
public func explicitlyDeprecated() {}
//--- ordering.swift
// CHECK-NOT: default @available
// We want multiple available attrs to show up in the right order.
#if TOP
default @available(*, deprecated, message: "first default")
default @available(*, deprecated, message: "second default")
#endif
// CHECK: @available(*, deprecated, message: "first default")
// CHECK-NEXT: @available(*, deprecated, message: "second default")
// CHECK-NEXT: public func defaultedOrderedFunc()
public func defaultedOrderedFunc() {}
// CHECK: @available(*, deprecated, message: "first default")
// CHECK-NEXT: @available(*, deprecated, message: "second default")
// CHECK-NEXT: @available(*, deprecated, message: "explicit")
// CHECK-NEXT: public func orderedFunc()
@available(*, deprecated, message: "explicit")
public func orderedFunc() {}
#if BOTTOM
default @available(*, deprecated, message: "first default")
default @available(*, deprecated, message: "second default")
#endif
//--- consumer.swift
import Legacy
import Ordering
func use() {
defaultedFunc() // expected-warning {{'defaultedFunc()' is deprecated: legacy module}}
_ = DefaultedClass() // expected-warning {{'DefaultedClass' is deprecated: legacy module}}
explicitlyDeprecated() // expected-warning {{'explicitlyDeprecated()' is deprecated: explicit}}
}
func useOrdering() {
// Last-listed default wins.
defaultedOrderedFunc() // expected-warning {{'defaultedOrderedFunc()' is deprecated: second default}}
orderedFunc() // expected-warning {{'orderedFunc()' is deprecated: explicit}}
}
//--- introduced.swift
default @available(MyLib_v1_0, *)
// INTRODUCED-NOT: default @available
// INTRODUCED: @available(watchOS 6.0, tvOS 13.0, macOS 10.15, iOS 13.0, *)
// INTRODUCED-NEXT: public func defaultedIntroduction()
public func defaultedIntroduction() {}
// A declaration can impose a stricter requirement than the file default.
// INTRODUCED-NEXT: @available(watchOS 6.0, tvOS 13.0, macOS 15.0, iOS 13.0, *)
// INTRODUCED-NEXT: public func stricterDeclaration()
@available(macOS 15.0, *)
public func stricterDeclaration() {}
//--- stricter_default.swift
default @available(macOS 15.0, *)
// A weaker explicit requirement must not relax the file default.
// INTRODUCED-NEXT: @available(macOS 15.0, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
// INTRODUCED-NEXT: public func stricterFileDefault()
@available(MyLib_v1_0, *)
public func stricterFileDefault() {}