Skip to content

Commit 763c2ed

Browse files
authored
Merge pull request #38329 from slavapestov/conformance-checker-disambiguate-availability
Sema: Check conditional availability earlier in conformance checking
2 parents 51ca7a1 + c508ef5 commit 763c2ed

File tree

3 files changed

+71
-10
lines changed

3 files changed

+71
-10
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,27 @@ bool WitnessChecker::findBestWitness(
13561356
}
13571357
}
13581358

1359+
// If there are multiple viable matches, drop any that are less available than the
1360+
// requirement.
1361+
if (numViable > 1) {
1362+
SmallVector<RequirementMatch, 2> checkedMatches;
1363+
bool foundCheckedMatch = false;
1364+
1365+
for (auto match : matches) {
1366+
if (!match.isViable()) {
1367+
checkedMatches.push_back(match);
1368+
} else if (checkWitness(requirement, match).Kind != CheckKind::Availability) {
1369+
foundCheckedMatch = true;
1370+
checkedMatches.push_back(match);
1371+
}
1372+
}
1373+
1374+
// If none of the matches were at least as available as the requirement, don't
1375+
// drop any of them; this will produce better diagnostics.
1376+
if (foundCheckedMatch)
1377+
std::swap(checkedMatches, matches);
1378+
}
1379+
13591380
if (numViable == 0) {
13601381
// Assume any missing value witnesses for a conformance in a module
13611382
// interface can be treated as opaque.

test/Sema/availability_versions.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,7 @@ protocol ProtocolWithRequirementMentioningUnavailable {
13851385

13861386
protocol HasMethodF {
13871387
associatedtype T
1388-
func f(_ p: T) // expected-note 4{{protocol requirement here}}
1388+
func f(_ p: T) // expected-note 3{{protocol requirement here}}
13891389
}
13901390

13911391
class TriesToConformWithFunctionIntroducedOn10_51 : HasMethodF {
@@ -1499,17 +1499,14 @@ extension TakesClassAvailableOn10_51_B : HasTakesClassAvailableOn10_51 {
14991499
}
15001500

15011501

1502-
// We do not want potential unavailability to play a role in picking a witness for a
1503-
// protocol requirement. Rather, the witness should be chosen, regardless of its
1504-
// potential unavailability, and then it should be diagnosed if it is less available
1505-
// than the protocol requires.
1506-
class TestAvailabilityDoesNotAffectWitnessCandidacy : HasMethodF {
1507-
// Test that we choose the more specialized witness even though it is
1508-
// less available than the protocol requires and there is a less specialized
1509-
// witness that has suitable availability.
1502+
// We want conditional availability to play a role in picking a witness for a
1503+
// protocol requirement.
1504+
class TestAvailabilityAffectsWitnessCandidacy : HasMethodF {
1505+
// Test that we choose the less specialized witness, because the more specialized
1506+
// witness is conditionally unavailable.
15101507

15111508
@available(OSX, introduced: 10.51)
1512-
func f(_ p: Int) { } // expected-error {{protocol 'HasMethodF' requires 'f' to be available in macOS 10.50.0 and newer}}
1509+
func f(_ p: Int) { }
15131510

15141511
func f<T>(_ p: T) { }
15151512
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-swift-frontend -emit-sil -verify %s | %FileCheck %s
2+
3+
// REQUIRES: OS=macosx
4+
5+
public protocol Potato {
6+
func eat()
7+
}
8+
9+
public protocol Fried {}
10+
11+
extension Potato {
12+
public func eat() {}
13+
}
14+
15+
@available(macOS 100, *)
16+
extension Potato where Self : Fried {
17+
public func eat() {}
18+
}
19+
20+
// We ought to pick the unconstrained Potato.eat(), not
21+
// the one from the extension, because the extension has
22+
// narrower availability than the conformance.
23+
public struct CurlyFries : Potato, Fried {}
24+
25+
public struct TaterTots {}
26+
27+
// This conformance on the other hand should use the
28+
// constrained Potato.eat(), since the generic signature
29+
// is more specific than the unconstrained protocol
30+
// extension.
31+
@available(macOS 100, *)
32+
extension TaterTots : Potato, Fried {}
33+
34+
// We FileCheck the SILGen output to verify that the correct
35+
// witnesses were chosen above.
36+
37+
// CHECK-LABEL: sil shared [transparent] [thunk] @$s37conformance_availability_disambiguate10CurlyFriesVAA6PotatoA2aDP3eatyyFTW : $@convention(witness_method: Potato) (@in_guaranteed CurlyFries) -> () {
38+
// CHECK: function_ref @$s37conformance_availability_disambiguate6PotatoPAAE3eatyyF : $@convention(method) <τ_0_0 where τ_0_0 : Potato> (@in_guaranteed τ_0_0) -> ()
39+
// CHECK: return
40+
41+
// sil shared [transparent] [thunk] @$s37conformance_availability_disambiguate9TaterTotsVAA6PotatoA2aDP3eatyyFTW : $@convention(witness_method: Potato) (@in_guaranteed TaterTots) -> () {
42+
// CHECK: function_ref @$s37conformance_availability_disambiguate6PotatoPA2A5FriedRzrlE3eatyyF : $@convention(method) <τ_0_0 where τ_0_0 : Fried, τ_0_0 : Potato> (@in_guaranteed τ_0_0) -> ()
43+
// CHECK: return

0 commit comments

Comments
 (0)