Skip to content

Commit b91e455

Browse files
committed
Worked out my confusion with existentials, and pulled out constraint fix checking into a separate function and try it with multiple fixes, if they exist.
1 parent 85ad4a1 commit b91e455

File tree

3 files changed

+82
-54
lines changed

3 files changed

+82
-54
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 68 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,69 @@ static const RequirementEnvironment &getOrCreateRequirementEnvironment(
678678
return cacheIter->getSecond();
679679
}
680680

681+
static Optional<RequirementMatch> findMissingGenericRequirementForSolutionFix(
682+
constraints::ConstraintFix *fix, ValueDecl *witness,
683+
ProtocolConformance *conformance,
684+
const RequirementEnvironment &reqEnvironment) {
685+
Type type, missingType;
686+
RequirementKind requirementKind;
687+
688+
using namespace constraints;
689+
690+
switch (fix->getKind()) {
691+
case FixKind::AddConformance: {
692+
auto missingConform = (MissingConformance *)fix;
693+
requirementKind = RequirementKind::Conformance;
694+
type = missingConform->getNonConformingType();
695+
missingType = missingConform->getProtocol()->getDeclaredType();
696+
break;
697+
}
698+
case FixKind::SkipSameTypeRequirement: {
699+
requirementKind = RequirementKind::SameType;
700+
auto requirementFix = (SkipSameTypeRequirement *)fix;
701+
type = requirementFix->lhsType();
702+
missingType = requirementFix->rhsType();
703+
break;
704+
}
705+
case FixKind::SkipSuperclassRequirement: {
706+
requirementKind = RequirementKind::Superclass;
707+
auto requirementFix = (SkipSuperclassRequirement *)fix;
708+
type = requirementFix->subclassType();
709+
missingType = requirementFix->superclassType();
710+
break;
711+
}
712+
default:
713+
return Optional<RequirementMatch>();
714+
}
715+
716+
auto missingRequirementMatch = [&](Type type) -> RequirementMatch {
717+
Requirement requirement(requirementKind, type, missingType);
718+
return RequirementMatch(witness, MatchKind::MissingRequirement,
719+
requirement);
720+
};
721+
722+
if (auto memberTy = type->getAs<DependentMemberType>())
723+
return missingRequirementMatch(type);
724+
725+
type = type->mapTypeOutOfContext();
726+
if (type->hasTypeParameter())
727+
if (auto env = conformance->getGenericEnvironment())
728+
if (auto assocType = env->mapTypeIntoContext(type))
729+
return missingRequirementMatch(assocType);
730+
731+
auto reqSubMap = reqEnvironment.getRequirementToSyntheticMap();
732+
auto proto = conformance->getProtocol();
733+
Type selfTy = proto->getSelfInterfaceType().subst(reqSubMap);
734+
if (type->isEqual(selfTy)) {
735+
type = conformance->getType();
736+
if (auto agt = type->getAs<AnyGenericType>())
737+
type = agt->getDecl()->getDeclaredInterfaceType();
738+
return missingRequirementMatch(type);
739+
}
740+
741+
return Optional<RequirementMatch>();
742+
}
743+
681744
RequirementMatch
682745
swift::matchWitness(TypeChecker &tc,
683746
WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
@@ -845,61 +908,13 @@ swift::matchWitness(TypeChecker &tc,
845908

846909
// If the types would match but for some other missing conformance, find and
847910
// call that out.
848-
if (solution && conformance && solution->Fixes.size() == 1) {
849-
auto fix = solution->Fixes.front();
850-
Type type, missingType;
851-
RequirementKind requirementKind;
852-
switch (fix->getKind()) {
853-
case FixKind::AddConformance: {
854-
auto missingConform = (MissingConformance *)fix;
855-
requirementKind = RequirementKind::Conformance;
856-
type = missingConform->getNonConformingType();
857-
missingType = missingConform->getProtocol()->getDeclaredType();
858-
break;
859-
}
860-
case FixKind::SkipSameTypeRequirement: {
861-
requirementKind = RequirementKind::SameType;
862-
auto requirementFix = (SkipSameTypeRequirement *)fix;
863-
type = requirementFix->lhsType();
864-
missingType = requirementFix->rhsType();
865-
break;
866-
}
867-
case FixKind::SkipSuperclassRequirement: {
868-
requirementKind = RequirementKind::Superclass;
869-
auto requirementFix = (SkipSuperclassRequirement *)fix;
870-
type = requirementFix->subclassType();
871-
missingType = requirementFix->superclassType();
872-
break;
873-
}
874-
default:
875-
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
876-
}
877-
878-
auto missingRequirementMatch = [&](Type type) -> RequirementMatch {
879-
Requirement requirement(requirementKind, type, missingType);
880-
return RequirementMatch(witness, MatchKind::MissingRequirement,
881-
requirement);
882-
};
883-
884-
if (auto memberTy = type->getAs<DependentMemberType>())
885-
return missingRequirementMatch(type);
886-
887-
type = type->mapTypeOutOfContext();
888-
if (type->hasTypeParameter())
889-
if (auto env = conformance->getGenericEnvironment())
890-
if (auto assocType = env->mapTypeIntoContext(type))
891-
return missingRequirementMatch(assocType);
892-
893-
auto reqSubMap = reqEnvironment.getRequirementToSyntheticMap();
894-
Type selfTy = proto->getSelfInterfaceType().subst(reqSubMap);
895-
if (type->isEqual(selfTy)) {
896-
type = conformance->getType();
897-
if (auto agt = type->getAs<AnyGenericType>())
898-
type = agt->getDecl()->getDeclaredInterfaceType();
899-
return missingRequirementMatch(type);
911+
if (solution && conformance && solution->Fixes.size()) {
912+
for (auto fix : solution->Fixes) {
913+
if (auto result = findMissingGenericRequirementForSolutionFix(
914+
fix, witness, conformance, reqEnvironment))
915+
return *result;
900916
}
901917
}
902-
903918
if (!solution || solution->Fixes.size())
904919
return RequirementMatch(witness, MatchKind::TypeConflict,
905920
witnessType);

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1747,7 +1747,8 @@ bool AssociatedTypeInference::diagnoseNoSolutions(
17471747
if (failed.Result.isError())
17481748
continue;
17491749

1750-
if (!failed.TypeWitness->getAnyNominal() &&
1750+
if ((!failed.TypeWitness->getAnyNominal() ||
1751+
failed.TypeWitness->isExistentialType()) &&
17511752
failed.Result.isConformanceRequirement()) {
17521753
diags.diagnose(failed.Witness,
17531754
diag::associated_type_witness_conform_impossible,

test/decl/protocol/req/missing_conformance.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,15 @@ extension P10 where A == Int {
9898
func bar() {} // expected-note {{candidate would match if 'A' was the same type as 'Int'}}
9999
}
100100
struct S2<A> : P10 {} // expected-error {{type 'S2<A>' does not conform to protocol 'P10'}}
101+
102+
protocol P11 {}
103+
protocol P12 {
104+
associatedtype A : P11 // expected-note {{unable to infer associated type 'A' for protocol 'P12'}}
105+
func bar() -> A
106+
}
107+
extension Int : P11 {}
108+
struct S3 : P12 { // expected-error {{type 'S3' does not conform to protocol 'P12'}}
109+
func bar() -> P11 { return 0 }
110+
// expected-note@-1 {{candidate can not infer 'A' = 'P11' because 'P11' is not a nominal type and so can't conform to 'P11'}}
111+
}
112+

0 commit comments

Comments
 (0)