Skip to content

Commit 546f22a

Browse files
authored
Merge pull request #40088 from DougGregor/async-witness-matching-resolution
2 parents 7b7443e + 293e316 commit 546f22a

File tree

4 files changed

+113
-9
lines changed

4 files changed

+113
-9
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/AST/AccessScope.h"
2929
#include "swift/AST/ClangModuleLoader.h"
3030
#include "swift/AST/Decl.h"
31+
#include "swift/AST/Effects.h"
3132
#include "swift/AST/ExistentialLayout.h"
3233
#include "swift/AST/GenericEnvironment.h"
3334
#include "swift/AST/GenericSignature.h"
@@ -930,6 +931,25 @@ static Optional<RequirementMatch> findMissingGenericRequirementForSolutionFix(
930931
return Optional<RequirementMatch>();
931932
}
932933

934+
/// Determine the set of effects on a given declaration.
935+
static PossibleEffects getEffects(ValueDecl *value) {
936+
if (auto func = dyn_cast<AbstractFunctionDecl>(value)) {
937+
PossibleEffects result;
938+
if (func->hasThrows())
939+
result |= EffectKind::Throws;
940+
if (func->hasAsync())
941+
result |= EffectKind::Async;
942+
return result;
943+
}
944+
945+
if (auto storage = dyn_cast<AbstractStorageDecl>(value)) {
946+
if (auto accessor = storage->getEffectfulGetAccessor())
947+
return getEffects(accessor);
948+
}
949+
950+
return PossibleEffects();
951+
}
952+
933953
RequirementMatch
934954
swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
935955
ProtocolDecl *proto, ProtocolConformance *conformance,
@@ -1107,12 +1127,17 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
11071127
return RequirementMatch(witness, MatchKind::TypeConflict,
11081128
witnessType);
11091129

1130+
MatchKind matchKind = MatchKind::ExactMatch;
1131+
if (hasAnyError(optionalAdjustments))
1132+
matchKind = MatchKind::OptionalityConflict;
1133+
else if (anyRenaming)
1134+
matchKind = MatchKind::RenamedMatch;
1135+
else if (getEffects(witness).containsOnly(getEffects(req)))
1136+
matchKind = MatchKind::FewerEffects;
1137+
11101138
// Success. Form the match result.
11111139
RequirementMatch result(witness,
1112-
hasAnyError(optionalAdjustments)
1113-
? MatchKind::OptionalityConflict
1114-
: anyRenaming ? MatchKind::RenamedMatch
1115-
: MatchKind::ExactMatch,
1140+
matchKind,
11161141
witnessType,
11171142
reqEnvironment,
11181143
optionalAdjustments);
@@ -2461,6 +2486,7 @@ diagnoseMatch(ModuleDecl *module, NormalProtocolConformance *conformance,
24612486
auto &diags = module->getASTContext().Diags;
24622487
switch (match.Kind) {
24632488
case MatchKind::ExactMatch:
2489+
case MatchKind::FewerEffects:
24642490
diags.diagnose(match.Witness, diag::protocol_witness_exact_match,
24652491
withAssocTypes);
24662492
break;
@@ -5746,7 +5772,7 @@ static void diagnosePotentialWitness(NormalProtocolConformance *conformance,
57465772
auto dc = conformance->getDeclContext();
57475773
auto match = matchWitness(oneUseCache, conformance->getProtocol(),
57485774
conformance, dc, req, witness);
5749-
if (match.Kind == MatchKind::ExactMatch &&
5775+
if (match.isWellFormed() &&
57505776
req->isObjC() && !witness->isObjC()) {
57515777
// Special case: note to add @objc.
57525778
auto diag =
@@ -6431,7 +6457,7 @@ swift::findWitnessedObjCRequirements(const ValueDecl *witness,
64316457
if (matchWitness(reqEnvCache, proto, *conformance,
64326458
witnessToMatch->getDeclContext(), req,
64336459
const_cast<ValueDecl *>(witnessToMatch))
6434-
.Kind == MatchKind::ExactMatch) {
6460+
.isWellFormed()) {
64356461
if (accessorKind) {
64366462
auto *storageReq = dyn_cast<AbstractStorageDecl>(req);
64376463
if (!storageReq)

lib/Sema/TypeCheckProtocol.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ enum class MatchKind : uint8_t {
212212
/// The witness matched the requirement exactly.
213213
ExactMatch,
214214

215+
/// The witness has fewer effects than the requirement, which is okay.
216+
FewerEffects,
217+
215218
/// There is a difference in optionality.
216219
OptionalityConflict,
217220

@@ -488,10 +491,47 @@ struct RequirementMatch {
488491
/// The matched derivative generic signature.
489492
GenericSignature DerivativeGenSig;
490493

491-
/// Determine whether this match is viable.
494+
/// Determine whether this match is well-formed, meaning that it is any
495+
/// difference determined by requirement matching is acceptable.
496+
bool isWellFormed() const {
497+
switch(Kind) {
498+
case MatchKind::ExactMatch:
499+
case MatchKind::FewerEffects:
500+
return true;
501+
502+
case MatchKind::OptionalityConflict:
503+
case MatchKind::RenamedMatch:
504+
case MatchKind::WitnessInvalid:
505+
case MatchKind::Circularity:
506+
case MatchKind::KindConflict:
507+
case MatchKind::TypeConflict:
508+
case MatchKind::MissingRequirement:
509+
case MatchKind::StaticNonStaticConflict:
510+
case MatchKind::SettableConflict:
511+
case MatchKind::PrefixNonPrefixConflict:
512+
case MatchKind::PostfixNonPostfixConflict:
513+
case MatchKind::MutatingConflict:
514+
case MatchKind::NonMutatingConflict:
515+
case MatchKind::ConsumingConflict:
516+
case MatchKind::RethrowsConflict:
517+
case MatchKind::RethrowsByConformanceConflict:
518+
case MatchKind::AsyncConflict:
519+
case MatchKind::ThrowsConflict:
520+
case MatchKind::NonObjC:
521+
case MatchKind::MissingDifferentiableAttr:
522+
case MatchKind::EnumCaseWithAssociatedValues:
523+
return false;
524+
}
525+
526+
llvm_unreachable("Unhandled MatchKind in switch.");
527+
}
528+
529+
/// Determine whether this match is viable, meaning that we could generate
530+
/// a witness for it, even though there might be semantic errors.
492531
bool isViable() const {
493532
switch(Kind) {
494533
case MatchKind::ExactMatch:
534+
case MatchKind::FewerEffects:
495535
case MatchKind::OptionalityConflict:
496536
case MatchKind::RenamedMatch:
497537
return true;
@@ -525,6 +565,7 @@ struct RequirementMatch {
525565
bool hasWitnessType() const {
526566
switch(Kind) {
527567
case MatchKind::ExactMatch:
568+
case MatchKind::FewerEffects:
528569
case MatchKind::RenamedMatch:
529570
case MatchKind::TypeConflict:
530571
case MatchKind::MissingRequirement:

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -767,8 +767,8 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitness(ValueDecl *req,
767767
// Match the witness. If we don't succeed, throw away the inference
768768
// information.
769769
// FIXME: A renamed match might be useful to retain for the failure case.
770-
if (matchWitness(dc, req, witness, setup, matchTypes, finalize)
771-
.Kind != MatchKind::ExactMatch) {
770+
if (!matchWitness(dc, req, witness, setup, matchTypes, finalize)
771+
.isWellFormed()) {
772772
inferred.Inferred.clear();
773773
}
774774

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
2+
3+
// Ensure that a protocol with async requirements can be conformed to by
4+
// non-async requirements, and that overloading works.
5+
protocol A {
6+
func foo()
7+
func foo() async
8+
9+
init()
10+
init() async
11+
12+
var property: Int { get async }
13+
14+
func bar() throws
15+
func bar() async throws
16+
}
17+
18+
struct A1: A {
19+
func foo() { }
20+
21+
var property: Int = 17
22+
23+
func bar() { }
24+
}
25+
26+
struct A2: A {
27+
func foo() { }
28+
func foo() async { }
29+
30+
init() { }
31+
init() async { }
32+
33+
var property: Int { get async { 5 } }
34+
35+
func bar() throws { }
36+
func bar() async throws { }
37+
}

0 commit comments

Comments
 (0)