Skip to content

Commit 54b8fbf

Browse files
committed
Revert "[ParseableInterfaces] Skip value witnesses of resilient conformances"
This reverts commit 61dd307, the effective part of swiftlang#20419. rdar://problem/43824088
1 parent e0a2670 commit 54b8fbf

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()) {
@@ -2892,23 +2909,6 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
28922909
}
28932910
}
28942911

2895-
ResolveWitnessResult
2896-
ConformanceChecker::resolveWitnessAsOpaque(ValueDecl *requirement) {
2897-
assert(!isa<AssociatedTypeDecl>(requirement) && "Use resolveTypeWitnessVia*");
2898-
auto match = matchWitness(TC, ReqEnvironmentCache, Proto,
2899-
Conformance, DC, requirement, requirement);
2900-
recordWitness(requirement, match);
2901-
return ResolveWitnessResult::Success;
2902-
}
2903-
2904-
static bool isConformanceFromParseableInterface(
2905-
const NormalProtocolConformance *conformance) {
2906-
auto *containingSF = conformance->getDeclContext()->getParentSourceFile();
2907-
if (!containingSF)
2908-
return false;
2909-
return containingSF->Kind == SourceFileKind::Interface;
2910-
}
2911-
29122912
ResolveWitnessResult
29132913
ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29142914
assert(!isa<AssociatedTypeDecl>(requirement) && "Use resolveTypeWitnessVia*");
@@ -2926,33 +2926,25 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29262926
}
29272927
}
29282928

2929-
// Determine whether we can get a witness for this requirement some other way.
2930-
bool hasFallbacks = false;
2931-
if (!hasFallbacks)
2932-
hasFallbacks = requirement->getAttrs().hasAttribute<OptionalAttr>();
2933-
if (!hasFallbacks)
2934-
hasFallbacks = requirement->getAttrs().isUnavailable(TC.Context);
2935-
if (!hasFallbacks)
2936-
hasFallbacks = isConformanceFromParseableInterface(Conformance);
2937-
2938-
if (!hasFallbacks) {
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-
hasFallbacks = 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);
2955-
}
2929+
// Determine whether we can derive a witness for this requirement.
2930+
bool canDerive = false;
2931+
2932+
// Can a witness for this requirement be derived for this nominal type?
2933+
if (auto derivable = DerivedConformance::getDerivableRequirement(
2934+
TC,
2935+
nominal,
2936+
requirement)) {
2937+
if (derivable == requirement) {
2938+
// If it's the same requirement, we can derive it here.
2939+
canDerive = true;
2940+
} else {
2941+
// Otherwise, go satisfy the derivable requirement, which can introduce
2942+
// a member that could in turn satisfy *this* requirement.
2943+
auto derivableProto = cast<ProtocolDecl>(derivable->getDeclContext());
2944+
if (auto conformance =
2945+
TC.conformsToProtocol(Adoptee, derivableProto, DC, None)) {
2946+
if (conformance->isConcrete())
2947+
(void)conformance->getConcrete()->getWitnessDecl(derivable, &TC);
29562948
}
29572949
}
29582950
}
@@ -2963,7 +2955,11 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
29632955
unsigned bestIdx = 0;
29642956
bool doNotDiagnoseMatches = false;
29652957
bool ignoringNames = false;
2966-
if (findBestWitness(requirement, hasFallbacks ? nullptr : &ignoringNames,
2958+
bool considerRenames =
2959+
!canDerive && !requirement->getAttrs().hasAttribute<OptionalAttr>() &&
2960+
!requirement->getAttrs().isUnavailable(TC.Context);
2961+
if (findBestWitness(requirement,
2962+
considerRenames ? &ignoringNames : nullptr,
29672963
Conformance,
29682964
/* out parameters: */
29692965
matches, numViable, bestIdx, doNotDiagnoseMatches)) {
@@ -3181,7 +3177,19 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
31813177
// We have either no matches or an ambiguous match.
31823178

31833179
// If we can derive a definition for this requirement, just call it missing.
3184-
if (hasFallbacks) {
3180+
if (canDerive) {
3181+
return ResolveWitnessResult::Missing;
3182+
}
3183+
3184+
// If the requirement is optional, it's okay. We'll satisfy this via
3185+
// our handling of default definitions.
3186+
//
3187+
// FIXME: revisit this once we get default definitions in protocol bodies.
3188+
//
3189+
// Treat 'unavailable' implicitly as if it were 'optional'.
3190+
// The compiler will reject actual uses.
3191+
auto Attrs = requirement->getAttrs();
3192+
if (Attrs.hasAttribute<OptionalAttr>() || Attrs.isUnavailable(TC.Context)) {
31853193
return ResolveWitnessResult::Missing;
31863194
}
31873195

@@ -3344,29 +3352,10 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
33443352

33453353
ResolveWitnessResult
33463354
ConformanceChecker::resolveWitnessTryingAllStrategies(ValueDecl *requirement) {
3347-
using ResolveWitnessStrategy =
3348-
decltype(&ConformanceChecker::resolveWitnessViaLookup);
3349-
static const constexpr ResolveWitnessStrategy defaultStrategies[] = {
3355+
decltype(&ConformanceChecker::resolveWitnessViaLookup) strategies[] = {
33503356
&ConformanceChecker::resolveWitnessViaLookup,
33513357
&ConformanceChecker::resolveWitnessViaDerivation,
33523358
&ConformanceChecker::resolveWitnessViaDefault};
3353-
ArrayRef<ResolveWitnessStrategy> strategies = defaultStrategies;
3354-
3355-
// Don't try any sort of derivation when processing a parseable interface.
3356-
if (isConformanceFromParseableInterface(Conformance)) {
3357-
if (Conformance->isResilient()) {
3358-
// Resilient conformances don't allow any sort of devirtualization, so
3359-
// don't bother looking up witnesses at all.
3360-
static const constexpr ResolveWitnessStrategy resilientStrategies[] = {
3361-
&ConformanceChecker::resolveWitnessAsOpaque};
3362-
strategies = resilientStrategies;
3363-
} else {
3364-
static const constexpr ResolveWitnessStrategy interfaceStrategies[] = {
3365-
&ConformanceChecker::resolveWitnessViaLookup,
3366-
&ConformanceChecker::resolveWitnessAsOpaque};
3367-
strategies = interfaceStrategies;
3368-
}
3369-
}
33703359

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

lib/Sema/TypeCheckProtocol.h

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

623-
/// Resolve the (non-type) witness as requiring dynamic dispatch.
624-
ResolveWitnessResult resolveWitnessAsOpaque(ValueDecl *requirement);
625-
626623
/// Resolve a (non-type) witness via name lookup.
627624
ResolveWitnessResult resolveWitnessViaLookup(ValueDecl *requirement);
628625

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)