Skip to content

Commit 3523847

Browse files
authored
Merge pull request #2703 from swiftwasm/release/5.4
[pull] swiftwasm-release/5.4 from release/5.4
2 parents eca7eb9 + ac8586e commit 3523847

15 files changed

+379
-12
lines changed

CHANGELOG.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,101 @@ CHANGELOG
2828
Swift 5.4
2929
---------
3030

31+
* Protocol conformance checking now considers `where` clauses when evaluating if a `typealias` is a suitable witness for an associated type requirement. The following code is now rejected:
32+
33+
```swift
34+
protocol Holder {
35+
associatedtype Contents
36+
}
37+
38+
struct Box<T> : Holder {}
39+
// error: type 'Box<T>' does not conform to protocol 'Holder'
40+
41+
extension Box where T : Hashable {
42+
typealias Contents = T
43+
}
44+
```
45+
46+
In most cases, the compiler would either crash or produce surprising results when making use of a `typealias` with an unsatisfied `where` clause, but it is possible that some previously-working code is now rejected. In the above example, the conformance can be fixed in one of various ways:
47+
48+
1) making it conditional (moving the `: Holder` from the definition of `Box` to the extension)
49+
2) moving the `typealias` from the extension to the type itself
50+
3) relaxing the `where` clause on the extension
51+
52+
* Availability checking now rejects protocols that refine less available protocols. Previously, this was accepted by the compiler but could result in linker errors or runtime crashes:
53+
54+
```swift
55+
@available(macOS 11, *)
56+
protocol Base {}
57+
58+
protocol Bad : Base {}
59+
// error: 'Base' is only available in macOS 11 or newer
60+
61+
@available(macOS 11, *)
62+
protocol Good : Base {} // OK
63+
```
64+
65+
* The `@available` attribute is no longer permitted on generic parameters, where it had no effect:
66+
67+
```swift
68+
struct Bad<@available(macOS 11, *) T> {}
69+
// error: '@available' attribute cannot be applied to this declaration
70+
71+
struct Good<T> {} // equivalent
72+
```
73+
74+
* If a type is made to conform to a protocol via an extension, the availability of the extension is now taken into account when forming generic types that use this protocol conformance. For example, consider a `Box` type whose conformance to `Hashable` uses features only available on macOS 11:
75+
76+
```swift
77+
public struct Box {}
78+
79+
@available(macOS 11, *)
80+
extension Box : Hashable {
81+
func hash(into: inout Hasher) {
82+
// call some new API to hash the value...
83+
}
84+
}
85+
86+
public func findBad(_: Set<Box>) -> Box {}
87+
// warning: conformance of 'Box' to 'Hashable' is only available in macOS 11 or newer
88+
89+
@available(macOS 11, *)
90+
public func findGood(_: Set<Box>) -> Box {} // OK
91+
```
92+
93+
In the above code, it is not valid for `findBad()` to take a `Set<Box>`, since `Set` requires that its element type conform to `Hashable`; however the conformance of `Box` to `Hashable` is not available prior to macOS 11.
94+
95+
Note that using an unavailable protocol conformance is a warning, not an error, to avoid potential source compatibility issues. This is because it was technically possible to write code in the past that made use of unavailable protocol conformances but worked anyway, if the optimizer had serendipitously eliminated all runtime dispatch through this conformance, or the code in question was entirely unreachable at runtime.
96+
97+
Protocol conformances can also be marked as completely unavailable or deprecated, by placing an appropriate `@available` attribute on the extension:
98+
99+
```swift
100+
@available(*, unavailable, message: "Not supported anymore")
101+
extension Box : Hashable {}
102+
103+
@available(*, deprecated, message: "Suggest using something else")
104+
extension Box : Hashable {}
105+
```
106+
107+
If a protocol conformance is defined on the type itself, it inherits availability from the type. You can move the protocol conformance to an extension if you need it to have narrower availability than the type.
108+
109+
* When `swift` is run with no arguments, it starts a REPL (read eval print loop) that uses LLDB. The compiler also had a second REPL implementation, known as the "integrated REPL", formerly accessible by running `swift -frontend -repl`. The "integrated REPL" was only intended for use by compiler developers, and has now been removed.
110+
111+
Note that this does not take away the ability to put Swift code in a script and run it with `swift myScript.swift`. This so-called "script mode" is distinct from the integrated REPL, and continues to be supported.
112+
113+
* Property wrappers now work in local contexts, making the following valid:
114+
115+
```swift
116+
@propertyWrapper
117+
struct Wrapper<T> {
118+
var wrappedValue: T
119+
}
120+
121+
func test() {
122+
@Wrapper var value = 10
123+
}
124+
```
125+
31126
* [SR-10069][]:
32127

33128
Function overloading now works in local contexts, making the following valid:

include/swift/AST/Decl.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,10 +2319,8 @@ class ValueDecl : public Decl {
23192319
/// dynamic methods on generic classes (see above).
23202320
bool isNativeMethodReplacement() const;
23212321

2322-
bool isEffectiveLinkageMoreVisibleThan(ValueDecl *other) const {
2323-
return (std::min(getEffectiveAccess(), AccessLevel::Public) >
2324-
std::min(other->getEffectiveAccess(), AccessLevel::Public));
2325-
}
2322+
/// Returns if this declaration has more visible formal access than 'other'.
2323+
bool isMoreVisibleThan(ValueDecl *other) const;
23262324

23272325
/// Set whether this type is 'dynamic' or not.
23282326
void setIsDynamic(bool value);

lib/AST/Decl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3416,6 +3416,23 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD,
34163416
llvm_unreachable("bad access level");
34173417
}
34183418

3419+
bool ValueDecl::isMoreVisibleThan(ValueDecl *other) const {
3420+
auto scope = getFormalAccessScope();
3421+
3422+
// 'other' may have come from a @testable import, so we need to upgrade it's
3423+
// visibility to public here. That is not the same as whether 'other' is
3424+
// being built with -enable-testing though -- we don't want to treat it
3425+
// differently in that case.
3426+
auto otherScope = other->getFormalAccessScope(getDeclContext());
3427+
3428+
if (scope.isPublic())
3429+
return !otherScope.isPublic();
3430+
else if (scope.isInternal())
3431+
return !otherScope.isPublic() && !otherScope.isInternal();
3432+
else
3433+
return false;
3434+
}
3435+
34193436
bool ValueDecl::isAccessibleFrom(const DeclContext *useDC,
34203437
bool forConformance,
34213438
bool allowUsableFromInline) const {

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2485,7 +2485,22 @@ static CanSILFunctionType getNativeSILFunctionType(
24852485
case SILFunctionType::Representation::Method:
24862486
case SILFunctionType::Representation::Closure:
24872487
case SILFunctionType::Representation::WitnessMethod: {
2488-
switch (constant ? constant->kind : SILDeclRef::Kind::Func) {
2488+
// FIXME: We should use origConstant unconditionally here, since in the
2489+
// case of protocol witness thunk type lowering, we want to lower the
2490+
// witness's calling convention according to the convention of the protocol
2491+
// requirement, even if the witness has a different kind. Previously we
2492+
// would base this on the witness `constant`, and this worked because
2493+
// witnesses had always been the same decl kind as the requirement, but
2494+
// enum cases as static witnesses broke this invariant.
2495+
//
2496+
// To minimize the change in behavior for Swift 5.4, we only consider
2497+
// origConstant when constant is an EnumElement, to avoid affecting other
2498+
// potential corner cases I'm not thinking of in the moment.
2499+
auto constantToTest = constant;
2500+
if (constant && constant->kind == SILDeclRef::Kind::EnumElement) {
2501+
constantToTest = origConstant;
2502+
}
2503+
switch (constantToTest ? constantToTest->kind : SILDeclRef::Kind::Func) {
24892504
case SILDeclRef::Kind::Initializer:
24902505
case SILDeclRef::Kind::EnumElement:
24912506
return getSILFunctionTypeForConventions(DefaultInitializerConventions());

lib/SILGen/SILGenApply.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4265,11 +4265,12 @@ bool SILGenModule::shouldEmitSelfAsRValue(FuncDecl *fn, CanType selfType) {
42654265

42664266
bool SILGenModule::isNonMutatingSelfIndirect(SILDeclRef methodRef) {
42674267
auto method = methodRef.getFuncDecl();
4268-
assert(method->getDeclContext()->isTypeContext());
4269-
assert(method->isNonMutating());
42704268
if (method->isStatic())
42714269
return false;
42724270

4271+
assert(method->getDeclContext()->isTypeContext());
4272+
assert(method->isNonMutating() || method->isConsuming());
4273+
42734274
auto fnType = M.Types.getConstantFunctionType(TypeExpansionContext::minimal(),
42744275
methodRef);
42754276
auto importAsMember = method->getImportAsMemberStatus();

lib/SILGen/SILGenType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass,
111111
bool baseLessVisibleThanDerived =
112112
(!usesObjCDynamicDispatch &&
113113
!derivedDecl->isFinal() &&
114-
derivedDecl->isEffectiveLinkageMoreVisibleThan(baseDecl));
114+
derivedDecl->isMoreVisibleThan(baseDecl));
115115

116116
// Determine the derived thunk type by lowering the derived type against the
117117
// abstraction pattern of the base.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ NeedsNewVTableEntryRequest::evaluate(Evaluator &evaluator,
10221022
// If the base is less visible than the override, we might need a vtable
10231023
// entry since callers of the override might not be able to see the base
10241024
// at all.
1025-
if (decl->isEffectiveLinkageMoreVisibleThan(base))
1025+
if (decl->isMoreVisibleThan(base))
10261026
return true;
10271027

10281028
using Direction = ASTContext::OverrideGenericSignatureReqCheck;

test/Driver/static-executable.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
// Create a self contained binary
2+
3+
// REQUIRES: rdar74148842
4+
// libc.a and libm.a have duplicate definitions of '__isnanl', so this test
5+
// fails to build.
6+
27
// REQUIRES: OS=linux-gnu
38
// REQUIRES: static_stdlib
49
print("hello world!")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
open class Base {
2+
public init() {}
3+
4+
internal func method() -> Int {
5+
return 1
6+
}
7+
}
8+
9+
open class Middle : Base {
10+
open override func method() -> Int {
11+
return super.method() + 1
12+
}
13+
}
14+
15+
public func callBaseMethod(_ b: Base) -> Int {
16+
return b.method()
17+
}
18+
19+
public func callMiddleMethod(_ m: Middle) -> Int {
20+
return m.method()
21+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// We test various combinations to make sure that -enable-testing does not
2+
// break ABI with or without -enable-library-evolution.
3+
4+
////
5+
6+
// RUN: %empty-directory(%t)
7+
8+
// 1) -enable-testing OFF / -enable-library-evolution OFF
9+
10+
// RUN: %target-build-swift-dylib(%t/%target-library-name(vtables_multifile_testable_helper)) %S/Inputs/vtables_multifile_testable_helper.swift -emit-module -emit-module-path %t/vtables_multifile_testable_helper.swiftmodule
11+
// RUN: %target-codesign %t/%target-library-name(vtables_multifile_testable_helper)
12+
13+
// RUN: %target-build-swift %s -L %t -I %t -lvtables_multifile_testable_helper -o %t/main %target-rpath(%t)
14+
// RUN: %target-codesign %t/main
15+
16+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
17+
18+
// 2) -enable-testing ON / -enable-library-evolution OFF
19+
20+
// ... first without rebuilding the client:
21+
22+
// RUN: %target-build-swift-dylib(%t/%target-library-name(vtables_multifile_testable_helper)) %S/Inputs/vtables_multifile_testable_helper.swift -enable-testing -emit-module -emit-module-path %t/vtables_multifile_testable_helper.swiftmodule
23+
// RUN: %target-codesign %t/%target-library-name(vtables_multifile_testable_helper)
24+
25+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
26+
27+
// ... now try to rebuild the client:
28+
29+
// RUN: %target-build-swift %s -L %t -I %t -lvtables_multifile_testable_helper -o %t/main %target-rpath(%t)
30+
// RUN: %target-codesign %t/main
31+
32+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
33+
34+
////
35+
36+
// Delete build artifacts
37+
// RUN: %empty-directory(%t)
38+
39+
// 3) -enable-testing OFF / -enable-library-evolution ON
40+
41+
// RUN: %target-build-swift-dylib(%t/%target-library-name(vtables_multifile_testable_helper)) %S/Inputs/vtables_multifile_testable_helper.swift -enable-library-evolution -emit-module -emit-module-path %t/vtables_multifile_testable_helper.swiftmodule
42+
// RUN: %target-codesign %t/%target-library-name(vtables_multifile_testable_helper)
43+
44+
// RUN: %target-build-swift %s -L %t -I %t -lvtables_multifile_testable_helper -o %t/main %target-rpath(%t)
45+
// RUN: %target-codesign %t/main
46+
47+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
48+
49+
// 4) -enable-testing ON / -enable-library-evolution ON
50+
51+
// ... first without rebuilding the client:
52+
53+
// RUN: %target-build-swift-dylib(%t/%target-library-name(vtables_multifile_testable_helper)) %S/Inputs/vtables_multifile_testable_helper.swift -enable-testing -enable-library-evolution -emit-module -emit-module-path %t/vtables_multifile_testable_helper.swiftmodule
54+
// RUN: %target-codesign %t/%target-library-name(vtables_multifile_testable_helper)
55+
56+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
57+
58+
// ... now try to rebuild the client:
59+
60+
// RUN: %target-build-swift %s -L %t -I %t -lvtables_multifile_testable_helper -o %t/main %target-rpath(%t)
61+
// RUN: %target-codesign %t/main
62+
63+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
64+
65+
////
66+
67+
// Delete build artifacts
68+
// RUN: %empty-directory(%t)
69+
70+
// 5) -enable-testing OFF / -enable-library-evolution ON / textual interfaces
71+
72+
// RUN: %target-build-swift-dylib(%t/%target-library-name(vtables_multifile_testable_helper)) %S/Inputs/vtables_multifile_testable_helper.swift -enable-library-evolution -emit-module-interface -emit-module-interface-path %t/vtables_multifile_testable_helper.swiftinterface
73+
// RUN: %target-codesign %t/%target-library-name(vtables_multifile_testable_helper)
74+
75+
// RUN: %target-build-swift %s -L %t -I %t -lvtables_multifile_testable_helper -o %t/main %target-rpath(%t)
76+
// RUN: %target-codesign %t/main
77+
78+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
79+
80+
// 6) -enable-testing ON / -enable-library-evolution ON / textual interfaces
81+
82+
// ... first without rebuilding the client:
83+
84+
// RUN: %target-build-swift-dylib(%t/%target-library-name(vtables_multifile_testable_helper)) %S/Inputs/vtables_multifile_testable_helper.swift -enable-testing -enable-library-evolution -emit-module-interface -emit-module-interface-path %t/vtables_multifile_testable_helper.swiftinterface
85+
// RUN: %target-codesign %t/%target-library-name(vtables_multifile_testable_helper)
86+
87+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
88+
89+
// ... now try to rebuild the client:
90+
91+
// RUN: %target-build-swift %s -L %t -I %t -lvtables_multifile_testable_helper -o %t/main %target-rpath(%t)
92+
// RUN: %target-codesign %t/main
93+
94+
// RUN: %target-run %t/main %t/%target-library-name(vtables_multifile_testable_helper)
95+
96+
97+
// REQUIRES: executable_test
98+
99+
import StdlibUnittest
100+
import vtables_multifile_testable_helper
101+
102+
var VTableTestSuite = TestSuite("VTable")
103+
104+
public class Derived : Middle {
105+
public override func method() -> Int {
106+
return super.method() + 1
107+
}
108+
}
109+
110+
VTableTestSuite.test("Derived") {
111+
expectEqual(3, callBaseMethod(Derived()))
112+
expectEqual(3, callMiddleMethod(Derived()))
113+
}
114+
115+
runAllTests()

0 commit comments

Comments
 (0)