2222#include " TypeCheckAvailability.h"
2323#include " TypeCheckConcurrency.h"
2424#include " TypeCheckDistributed.h"
25+ #include " TypeCheckEffects.h"
2526#include " TypeCheckObjC.h"
2627#include " swift/AST/ASTContext.h"
2728#include " swift/AST/ASTMangler.h"
@@ -589,6 +590,8 @@ RequirementMatch swift::matchWitness(
589590 // Perform basic matching of the requirement and witness.
590591 bool decomposeFunctionType = false ;
591592 bool ignoreReturnType = false ;
593+ Type reqThrownError;
594+ Type witnessThrownError;
592595 if (isa<FuncDecl>(req) && isa<FuncDecl>(witness)) {
593596 auto funcReq = cast<FuncDecl>(req);
594597 auto funcWitness = cast<FuncDecl>(witness);
@@ -681,12 +684,36 @@ RequirementMatch swift::matchWitness(
681684 MatchKind::MutatingConflict);
682685 }
683686
687+ // Check for async mismatches.
688+ if (!witnessASD->isLessEffectfulThan (reqASD, EffectKind::Async)) {
689+ return RequirementMatch (
690+ getStandinForAccessor (witnessASD, AccessorKind::Get),
691+ MatchKind::AsyncConflict);
692+ }
693+
684694 // Check that the witness has no more effects than the requirement.
685695 if (auto problem = checkEffects (witnessASD, reqASD))
686696 return problem.value ();
687697
688698 // Decompose the parameters for subscript declarations.
689699 decomposeFunctionType = isa<SubscriptDecl>(req);
700+
701+ // Dig out the thrown error types from the getter so we can compare them
702+ // later.
703+ auto getThrownErrorType = [](AbstractStorageDecl *asd) -> Type {
704+ if (auto getter = asd->getEffectfulGetAccessor ()) {
705+ if (Type thrownErrorType = getter->getThrownInterfaceType ()) {
706+ return thrownErrorType;
707+ } else if (getter->hasThrows ()) {
708+ return asd->getASTContext ().getAnyExistentialType ();
709+ }
710+ }
711+
712+ return asd->getASTContext ().getNeverType ();
713+ };
714+
715+ reqThrownError = getThrownErrorType (reqASD);
716+ witnessThrownError = getThrownErrorType (witnessASD);
690717 } else if (isa<ConstructorDecl>(witness)) {
691718 decomposeFunctionType = true ;
692719 ignoreReturnType = true ;
@@ -831,12 +858,11 @@ RequirementMatch swift::matchWitness(
831858 return RequirementMatch (witness, MatchKind::AsyncConflict);
832859 }
833860
834- // If the witness is 'throws', the requirement must be.
835- // FIXME: We need the same matching we do in the constraint solver,
836- // with the same fast paths for obvious throws/nonthrows cases.
837- if (witnessFnType->getExtInfo ().isThrowing () &&
838- !reqFnType->getExtInfo ().isThrowing ()) {
839- return RequirementMatch (witness, MatchKind::ThrowsConflict);
861+ if (!reqThrownError) {
862+ // Save the thrown error types of the requirement and witness so we
863+ // can check them later.
864+ reqThrownError = getEffectiveThrownErrorTypeOrNever (reqFnType);
865+ witnessThrownError = getEffectiveThrownErrorTypeOrNever (witnessFnType);
840866 }
841867 }
842868 } else {
@@ -859,6 +885,35 @@ RequirementMatch swift::matchWitness(
859885 }
860886 }
861887
888+ // Check the thrown error types. This includes 'any Error' and 'Never' for
889+ // untyped throws and non-throwing cases as well.
890+ if (reqThrownError && witnessThrownError) {
891+ auto thrownErrorTypes = getTypesToCompare (
892+ req, reqThrownError, false , witnessThrownError, false ,
893+ VarianceKind::None);
894+
895+ Type reqThrownError = std::get<0 >(thrownErrorTypes);
896+ Type witnessThrownError = std::get<1 >(thrownErrorTypes);
897+ switch (compareThrownErrorsForSubtyping (witnessThrownError, reqThrownError,
898+ dc)) {
899+ case ThrownErrorSubtyping::DropsThrows:
900+ case ThrownErrorSubtyping::Mismatch:
901+ return RequirementMatch (witness, MatchKind::ThrowsConflict);
902+
903+ case ThrownErrorSubtyping::ExactMatch:
904+ case ThrownErrorSubtyping::Subtype:
905+ // All is well.
906+ break ;
907+
908+ case ThrownErrorSubtyping::Dependent:
909+ // We need to perform type matching
910+ if (auto result = matchTypes (witnessThrownError, reqThrownError)) {
911+ return std::move (result.value ());
912+ }
913+ break ;
914+ }
915+ }
916+
862917 // Now finalize the match.
863918 auto result = finalize (anyRenaming, optionalAdjustments);
864919 // Check if the requirement's `@differentiable` attributes are satisfied by
0 commit comments