Skip to content

Commit 0b320a6

Browse files
committed
Sema: Implement DefaultWitnessChecker
Now that WitnessChecker is separate from ConformanceChecker, implement a DefaultWitnessChecker subclass which performs default witness resolution. This populates the recently-added ProtocolDecl::DefaultWitnesses map. Unlike ConformanceChecker, the DefaultWitnessChecker looks up the witness in any protocol extensions of the protocol, matching the context archetypes of the requirement against the witness. For now, we infer default witnesses for all protocols, but don't do anything with that information. An upcoming SILGen patch will start to emit thunks and add tests.
1 parent 681a613 commit 0b320a6

File tree

6 files changed

+90
-1
lines changed

6 files changed

+90
-1
lines changed

include/swift/Subsystems.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ namespace swift {
165165
OptionSet<TypeCheckingFlags> Options,
166166
unsigned StartElem = 0);
167167

168+
/// Once type checking is complete, this walks protocol requirements
169+
/// to resolve default witnesses.
170+
void finishTypeChecking(SourceFile &SF);
171+
168172
/// Now that we have type-checked an entire module, perform any type
169173
/// checking that requires the full module, e.g., Objective-C method
170174
/// override checking.

lib/Frontend/Frontend.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,11 @@ void CompilerInstance::performSema() {
516516
if (auto SF = dyn_cast<SourceFile>(File))
517517
performWholeModuleTypeChecking(*SF);
518518
}
519+
520+
for (auto File : MainModule->getFiles())
521+
if (auto SF = dyn_cast<SourceFile>(File))
522+
if (PrimaryBufferID == NO_SUCH_BUFFER || SF == PrimarySourceFile)
523+
finishTypeChecking(*SF);
519524
}
520525

521526
void CompilerInstance::performParseOnly() {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4137,6 +4137,74 @@ Type TypeChecker::deriveTypeWitness(DeclContext *DC,
41374137
}
41384138
}
41394139

4140+
namespace {
4141+
class DefaultWitnessChecker : public WitnessChecker {
4142+
4143+
public:
4144+
DefaultWitnessChecker(TypeChecker &tc,
4145+
ProtocolDecl *proto)
4146+
: WitnessChecker(tc, proto, proto->getDeclaredType(), proto) { }
4147+
4148+
ResolveWitnessResult resolveWitnessViaLookup(ValueDecl *requirement);
4149+
void recordWitness(ValueDecl *requirement, const RequirementMatch &match);
4150+
};
4151+
}
4152+
4153+
ResolveWitnessResult
4154+
DefaultWitnessChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
4155+
assert(!isa<AssociatedTypeDecl>(requirement) && "Must be a value witness");
4156+
4157+
// Find the best default witness for the requirement.
4158+
SmallVector<RequirementMatch, 4> matches;
4159+
unsigned numViable = 0;
4160+
unsigned bestIdx = 0;
4161+
bool doNotDiagnoseMatches = false;
4162+
4163+
if (findBestWitness(
4164+
requirement, nullptr, nullptr,
4165+
/* out parameters: */
4166+
matches, numViable, bestIdx, doNotDiagnoseMatches)) {
4167+
4168+
auto &best = matches[bestIdx];
4169+
4170+
// Perform the same checks as conformance witness matching, but silently
4171+
// ignore the candidate instead of diagnosing anything.
4172+
auto check = checkWitness(Accessibility::Public, requirement, best);
4173+
if (check.Kind != CheckKind::Success)
4174+
return ResolveWitnessResult::ExplicitFailed;
4175+
4176+
// Record the match.
4177+
recordWitness(requirement, best);
4178+
return ResolveWitnessResult::Success;
4179+
}
4180+
4181+
// We have either no matches or an ambiguous match.
4182+
return ResolveWitnessResult::Missing;
4183+
}
4184+
4185+
void DefaultWitnessChecker::recordWitness(ValueDecl *requirement,
4186+
const RequirementMatch &match) {
4187+
Proto->setDefaultWitness(requirement, match.getWitness(TC.Context));
4188+
4189+
// FIXME: Synthesize accessors (or really, just materializeForSet) if this
4190+
// is a computed property?
4191+
}
4192+
4193+
void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) {
4194+
DefaultWitnessChecker checker(*this, proto);
4195+
4196+
for (auto *requirement : proto->getMembers()) {
4197+
if (isa<AssociatedTypeDecl>(requirement))
4198+
continue;
4199+
4200+
if (requirement->isInvalid())
4201+
continue;
4202+
4203+
if (auto *valueDecl = dyn_cast<ValueDecl>(requirement))
4204+
checker.resolveWitnessViaLookup(valueDecl);
4205+
}
4206+
}
4207+
41404208
bool TypeChecker::isProtocolExtensionUsable(DeclContext *dc, Type type,
41414209
ExtensionDecl *protocolExtension) {
41424210
using namespace constraints;

lib/Sema/TypeChecker.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,15 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC,
624624
}
625625
}
626626

627+
void swift::finishTypeChecking(SourceFile &SF) {
628+
auto &Ctx = SF.getASTContext();
629+
TypeChecker TC(Ctx);
630+
631+
for (auto D : SF.Decls)
632+
if (auto PD = dyn_cast<ProtocolDecl>(D))
633+
TC.inferDefaultWitnesses(PD);
634+
}
635+
627636
void swift::performWholeModuleTypeChecking(SourceFile &SF) {
628637
auto &Ctx = SF.getASTContext();
629638
Ctx.diagnoseAttrsRequiringFoundation(SF);

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,9 @@ class TypeChecker final : public LazyResolver {
895895
AnyFunctionType::ExtInfo
896896
applyFunctionTypeAttributes(AbstractFunctionDecl *func, unsigned i);
897897

898+
/// Infer default value witnesses for all requirements in the given protocol.
899+
void inferDefaultWitnesses(ProtocolDecl *proto);
900+
898901
/// Determine whether the given (potentially constrained) protocol extension
899902
/// is usable for the given type.
900903
bool isProtocolExtensionUsable(DeclContext *dc, Type type,

test/NameBinding/reference-dependencies.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ private struct ThreeTildeTypeImpl : ThreeTildeType {
126126
func overloadedOnProto<T>(_: T) {}
127127
func overloadedOnProto<T: ThreeTildeType>(_: T) {}
128128

129-
// CHECK-DAG: !private "~~~"
129+
// CHECK-DAG: - "~~~"
130130
private prefix func ~~~(_: ThreeTildeTypeImpl) {}
131131

132132
var topLevelComputedProperty: Bool {

0 commit comments

Comments
 (0)