Skip to content

Commit 81bcf9d

Browse files
authored
Revert "[ParseableInterfaces] Skip value witnesses of resilient conformances" (#20637)
This reverts commit 61dd307, the effective part of #20419. rdar://problem/43824088
1 parent 018498f commit 81bcf9d

File tree

4 files changed

+55
-85
lines changed

4 files changed

+55
-85
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 55 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,23 @@ bool WitnessChecker::findBestWitness(
11731173
}
11741174

11751175
if (numViable == 0) {
1176+
// Assume any missing value witnesses for a conformance in a parseable
1177+
// interface can be treated as opaque.
1178+
// FIXME: ...but we should do something better about types.
1179+
if (conformance && !conformance->isInvalid()) {
1180+
if (auto *SF = DC->getParentSourceFile()) {
1181+
if (SF->Kind == SourceFileKind::Interface) {
1182+
auto match = matchWitness(TC, ReqEnvironmentCache, Proto,
1183+
conformance, DC, requirement, requirement);
1184+
assert(match.isViable());
1185+
numViable = 1;
1186+
bestIdx = matches.size();
1187+
matches.push_back(std::move(match));
1188+
return true;
1189+
}
1190+
}
1191+
}
1192+
11761193
if (anyFromUnconstrainedExtension &&
11771194
conformance != nullptr &&
11781195
conformance->isInvalid()) {
@@ -2899,23 +2916,6 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
28992916
}
29002917
}
29012918

2902-
ResolveWitnessResult
2903-
ConformanceChecker::resolveWitnessAsOpaque(ValueDecl *requirement) {
2904-
assert(!isa<AssociatedTypeDecl>(requirement) && "Use resolveTypeWitnessVia*");
2905-
auto match = matchWitness(TC, ReqEnvironmentCache, Proto,
2906-
Conformance, DC, requirement, requirement);
2907-
recordWitness(requirement, match);
2908-
return ResolveWitnessResult::Success;
2909-
}
2910-
2911-
static bool isConformanceFromParseableInterface(
2912-
const NormalProtocolConformance *conformance) {
2913-
auto *containingSF = conformance->getDeclContext()->getParentSourceFile();
2914-
if (!containingSF)
2915-
return false;
2916-
return containingSF->Kind == SourceFileKind::Interface;
2917-
}
2918-
29192919
ResolveWitnessResult
29202920
ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29212921
assert(!isa<AssociatedTypeDecl>(requirement) && "Use resolveTypeWitnessVia*");
@@ -2933,33 +2933,25 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29332933
}
29342934
}
29352935

2936-
// Determine whether we can get a witness for this requirement some other way.
2937-
bool hasFallbacks = false;
2938-
if (!hasFallbacks)
2939-
hasFallbacks = requirement->getAttrs().hasAttribute<OptionalAttr>();
2940-
if (!hasFallbacks)
2941-
hasFallbacks = requirement->getAttrs().isUnavailable(TC.Context);
2942-
if (!hasFallbacks)
2943-
hasFallbacks = isConformanceFromParseableInterface(Conformance);
2944-
2945-
if (!hasFallbacks) {
2946-
// Can a witness for this requirement be derived for this nominal type?
2947-
if (auto derivable = DerivedConformance::getDerivableRequirement(
2948-
TC,
2949-
nominal,
2950-
requirement)) {
2951-
if (derivable == requirement) {
2952-
// If it's the same requirement, we can derive it here.
2953-
hasFallbacks = true;
2954-
} else {
2955-
// Otherwise, go satisfy the derivable requirement, which can introduce
2956-
// a member that could in turn satisfy *this* requirement.
2957-
auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext());
2958-
if (auto conformance =
2959-
TC.conformsToProtocol(Adoptee, derivableProto, DC, None)) {
2960-
if (conformance->isConcrete())
2961-
(void)conformance->getConcrete()->getWitnessDecl(derivable, &TC);
2962-
}
2936+
// Determine whether we can derive a witness for this requirement.
2937+
bool canDerive = false;
2938+
2939+
// Can a witness for this requirement be derived for this nominal type?
2940+
if (auto derivable = DerivedConformance::getDerivableRequirement(
2941+
TC,
2942+
nominal,
2943+
requirement)) {
2944+
if (derivable == requirement) {
2945+
// If it's the same requirement, we can derive it here.
2946+
canDerive = true;
2947+
} else {
2948+
// Otherwise, go satisfy the derivable requirement, which can introduce
2949+
// a member that could in turn satisfy *this* requirement.
2950+
auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext());
2951+
if (auto conformance =
2952+
TC.conformsToProtocol(Adoptee, derivableProto, DC, None)) {
2953+
if (conformance->isConcrete())
2954+
(void)conformance->getConcrete()->getWitnessDecl(derivable, &TC);
29632955
}
29642956
}
29652957
}
@@ -2970,7 +2962,11 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29702962
unsigned bestIdx = 0;
29712963
bool doNotDiagnoseMatches = false;
29722964
bool ignoringNames = false;
2973-
if (findBestWitness(requirement, hasFallbacks ? nullptr : &ignoringNames,
2965+
bool considerRenames =
2966+
!canDerive && !requirement->getAttrs().hasAttribute<OptionalAttr>() &&
2967+
!requirement->getAttrs().isUnavailable(TC.Context);
2968+
if (findBestWitness(requirement,
2969+
considerRenames ? &ignoringNames : nullptr,
29742970
Conformance,
29752971
/* out parameters: */
29762972
matches, numViable, bestIdx, doNotDiagnoseMatches)) {
@@ -3192,7 +3188,19 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
31923188
// We have either no matches or an ambiguous match.
31933189

31943190
// If we can derive a definition for this requirement, just call it missing.
3195-
if (hasFallbacks) {
3191+
if (canDerive) {
3192+
return ResolveWitnessResult::Missing;
3193+
}
3194+
3195+
// If the requirement is optional, it's okay. We'll satisfy this via
3196+
// our handling of default definitions.
3197+
//
3198+
// FIXME: revisit this once we get default definitions in protocol bodies.
3199+
//
3200+
// Treat 'unavailable' implicitly as if it were 'optional'.
3201+
// The compiler will reject actual uses.
3202+
auto Attrs = requirement->getAttrs();
3203+
if (Attrs.hasAttribute<OptionalAttr>() || Attrs.isUnavailable(TC.Context)) {
31963204
return ResolveWitnessResult::Missing;
31973205
}
31983206

@@ -3355,29 +3363,10 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
33553363

33563364
ResolveWitnessResult
33573365
ConformanceChecker::resolveWitnessTryingAllStrategies(ValueDecl *requirement) {
3358-
using ResolveWitnessStrategy =
3359-
decltype(&ConformanceChecker::resolveWitnessViaLookup);
3360-
static const constexpr ResolveWitnessStrategy defaultStrategies[] = {
3366+
decltype(&ConformanceChecker::resolveWitnessViaLookup) strategies[] = {
33613367
&ConformanceChecker::resolveWitnessViaLookup,
33623368
&ConformanceChecker::resolveWitnessViaDerivation,
33633369
&ConformanceChecker::resolveWitnessViaDefault};
3364-
ArrayRef<ResolveWitnessStrategy> strategies = defaultStrategies;
3365-
3366-
// Don't try any sort of derivation when processing a parseable interface.
3367-
if (isConformanceFromParseableInterface(Conformance)) {
3368-
if (Conformance->isResilient()) {
3369-
// Resilient conformances don't allow any sort of devirtualization, so
3370-
// don't bother looking up witnesses at all.
3371-
static const constexpr ResolveWitnessStrategy resilientStrategies[] = {
3372-
&ConformanceChecker::resolveWitnessAsOpaque};
3373-
strategies = resilientStrategies;
3374-
} else {
3375-
static const constexpr ResolveWitnessStrategy interfaceStrategies[] = {
3376-
&ConformanceChecker::resolveWitnessViaLookup,
3377-
&ConformanceChecker::resolveWitnessAsOpaque};
3378-
strategies = interfaceStrategies;
3379-
}
3380-
}
33813370

33823371
for (auto strategy : strategies) {
33833372
ResolveWitnessResult result = (this->*strategy)(requirement);

lib/Sema/TypeCheckProtocol.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -623,9 +623,6 @@ class ConformanceChecker : public WitnessChecker {
623623
void checkNonFinalClassWitness(ValueDecl *requirement,
624624
ValueDecl *witness);
625625

626-
/// Resolve the (non-type) witness as requiring dynamic dispatch.
627-
ResolveWitnessResult resolveWitnessAsOpaque(ValueDecl *requirement);
628-
629626
/// Resolve a (non-type) witness via name lookup.
630627
ResolveWitnessResult resolveWitnessViaLookup(ValueDecl *requirement);
631628

test/ParseableInterface/Conformances.swiftinterface

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,6 @@ public struct OpaqueStructImpl: MyProto {}
4848
// CHECK: function_ref @$s12Conformances7MyProtoPyS2icig
4949
// CHECK: end sil function '$s16ConformancesUser10testOpaqueSiyF'
5050

51-
public struct ResilientStructImpl: MyProto {
52-
@available(*, unavailable) // Ignore this, because the conformance is resilient.
53-
public init()
54-
}
55-
56-
// CHECK-LABEL: sil @$s16ConformancesUser13testResilientSiyF
57-
// CHECK: witness_method $ResilientStructImpl, #MyProto.init!allocator.1
58-
// CHECK: witness_method $ResilientStructImpl, #MyProto.method!1
59-
// CHECK: witness_method $ResilientStructImpl, #MyProto.prop!setter.1
60-
// CHECK: witness_method $ResilientStructImpl, #MyProto.subscript!getter.1
61-
// CHECK: end sil function '$s16ConformancesUser13testResilientSiyF'
62-
6351

6452
@objc public protocol OptionalReqs {
6553
@objc optional func method()

test/ParseableInterface/Inputs/ConformancesUser.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ public func testOpaque() -> Int {
1515
return testGeneric(OpaqueStructImpl.self)
1616
}
1717

18-
public func testResilient() -> Int {
19-
return testGeneric(ResilientStructImpl.self)
20-
}
21-
2218

2319
func testOptionalGeneric<T: OptionalReqs>(_ obj: T) -> Bool {
2420
return obj.method?() != nil

0 commit comments

Comments
 (0)