Skip to content

Commit 821c3a3

Browse files
committed
Sema: Introduce ResolveValueWitnessesRequest
1 parent bbbfc62 commit 821c3a3

File tree

5 files changed

+133
-104
lines changed

5 files changed

+133
-104
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,6 +2910,24 @@ class ValueWitnessRequest
29102910
void cacheResult(Witness value) const;
29112911
};
29122912

2913+
class ResolveValueWitnessesRequest
2914+
: public SimpleRequest<ResolveValueWitnessesRequest,
2915+
evaluator::SideEffect(NormalProtocolConformance *),
2916+
RequestFlags::Cached> {
2917+
public:
2918+
using SimpleRequest::SimpleRequest;
2919+
2920+
private:
2921+
friend SimpleRequest;
2922+
2923+
// Evaluation.
2924+
evaluator::SideEffect
2925+
evaluate(Evaluator &evaluator, NormalProtocolConformance *conformance) const;
2926+
2927+
public:
2928+
bool isCached() const { return true; }
2929+
};
2930+
29132931
class AssociatedConformanceRequest
29142932
: public SimpleRequest<AssociatedConformanceRequest,
29152933
ProtocolConformanceRef(NormalProtocolConformance *,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,9 @@ SWIFT_REQUEST(TypeChecker, ResolveTypeWitnessesRequest,
438438
SWIFT_REQUEST(TypeChecker, ValueWitnessRequest,
439439
Witness(NormalProtocolConformance *, ValueDecl *),
440440
SeparatelyCached, NoLocationInfo)
441+
SWIFT_REQUEST(TypeChecker, ResolveValueWitnessesRequest,
442+
evaluator::SideEffect(NormalProtocolConformance *),
443+
Cached, NoLocationInfo)
441444
SWIFT_REQUEST(TypeChecker, PatternTypeRequest,
442445
Type(ContextualPattern),
443446
Cached, HasNearestLocation)

lib/Sema/CSDiagnostics.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3454,19 +3454,24 @@ bool ContextualFailure::tryProtocolConformanceFixIt(
34543454
llvm::raw_svector_ostream SS(Text);
34553455
llvm::SmallVector<NormalProtocolConformance *, 2> fakeConformances;
34563456
for (auto protocol : missingProtocols) {
3457+
// Create a fake conformance for this type to the given protocol.
34573458
auto conformance = getASTContext().getNormalConformance(
34583459
nominal->getSelfInterfaceType(), protocol, SourceLoc(), nominal,
34593460
ProtocolConformanceState::Incomplete, /*isUnchecked=*/false,
34603461
/*isPreconcurrency=*/false);
3461-
// Type witnesses must be resolved first.
3462+
3463+
// Resolve the conformance to generate fixits.
34623464
evaluateOrDefault(getASTContext().evaluator,
34633465
ResolveTypeWitnessesRequest{conformance},
34643466
evaluator::SideEffect());
3465-
ConformanceChecker checker(getASTContext(), conformance);
3466-
checker.resolveValueWitnesses();
3467+
evaluateOrDefault(getASTContext().evaluator,
3468+
ResolveValueWitnessesRequest{conformance},
3469+
evaluator::SideEffect());
3470+
34673471
fakeConformances.push_back(conformance);
34683472
}
34693473

3474+
// Collect all of the fixits generated above.
34703475
for (auto conformance : fakeConformances) {
34713476
auto missingWitnesses = getASTContext().takeDelayedMissingWitnesses(conformance);
34723477
for (auto decl : missingWitnesses) {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 104 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,6 +2168,9 @@ static bool hasAdditionalSemanticChecks(ProtocolDecl *proto) {
21682168
return proto->isSpecificProtocol(KnownProtocolKind::Sendable);
21692169
}
21702170

2171+
static void ensureRequirementsAreSatisfied(ASTContext &ctx,
2172+
NormalProtocolConformance *conformance);
2173+
21712174
/// Determine whether the type \c T conforms to the protocol \c Proto,
21722175
/// recording the complete witness table if it does.
21732176
void MultiConformanceChecker::
@@ -2191,7 +2194,6 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
21912194
auto Proto = conformance->getProtocol();
21922195
auto ProtoType = Proto->getDeclaredInterfaceType();
21932196
SourceLoc ComplainLoc = conformance->getLoc();
2194-
auto &C = ProtoType->getASTContext();
21952197

21962198
// Note that we are checking this conformance now.
21972199
conformance->setState(ProtocolConformanceState::Checking);
@@ -2205,27 +2207,27 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
22052207

22062208
// If the protocol requires a class, non-classes are a non-starter.
22072209
if (Proto->requiresClass() && !DC->getSelfClassDecl()) {
2208-
C.Diags.diagnose(ComplainLoc,
2209-
diag::non_class_cannot_conform_to_class_protocol, T,
2210-
ProtoType);
2210+
Context.Diags.diagnose(ComplainLoc,
2211+
diag::non_class_cannot_conform_to_class_protocol, T,
2212+
ProtoType);
22112213
conformance->setInvalid();
22122214
return;
22132215
}
22142216

22152217
if (T->isActorType()) {
22162218
if (auto globalActor = Proto->getGlobalActorAttr()) {
2217-
C.Diags.diagnose(ComplainLoc,
2218-
diag::actor_cannot_conform_to_global_actor_protocol, T,
2219-
ProtoType);
2219+
Context.Diags.diagnose(ComplainLoc,
2220+
diag::actor_cannot_conform_to_global_actor_protocol, T,
2221+
ProtoType);
22202222

22212223
CustomAttr *attr;
22222224
NominalTypeDecl *actor;
22232225

22242226
std::tie(attr, actor) = *globalActor;
22252227

2226-
C.Diags.diagnose(attr->getLocation(),
2227-
diag::protocol_isolated_to_global_actor_here, ProtoType,
2228-
actor->getDeclaredInterfaceType());
2228+
Context.Diags.diagnose(attr->getLocation(),
2229+
diag::protocol_isolated_to_global_actor_here, ProtoType,
2230+
actor->getDeclaredInterfaceType());
22292231

22302232
conformance->setInvalid();
22312233
return;
@@ -2248,7 +2250,7 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
22482250
break;
22492251
}
22502252
if (diagKind) {
2251-
C.Diags.diagnose(ComplainLoc, diagKind.value(), T, ProtoType);
2253+
Context.Diags.diagnose(ComplainLoc, diagKind.value(), T, ProtoType);
22522254
conformance->setInvalid();
22532255
return;
22542256
}
@@ -2260,9 +2262,9 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
22602262
// with the Obj-C runtime when they're satisfied, but we'd still have solve
22612263
// the problem with extensions that we check for below.
22622264
if (!conformance->getConditionalRequirements().empty()) {
2263-
C.Diags.diagnose(ComplainLoc,
2264-
diag::objc_protocol_cannot_have_conditional_conformance,
2265-
T, ProtoType);
2265+
Context.Diags.diagnose(ComplainLoc,
2266+
diag::objc_protocol_cannot_have_conditional_conformance,
2267+
T, ProtoType);
22662268
conformance->setInvalid();
22672269
return;
22682270
}
@@ -2274,9 +2276,9 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
22742276
if (auto classDecl = ext->getSelfClassDecl()) {
22752277
if (classDecl->isGenericContext()) {
22762278
if (!classDecl->isTypeErasedGenericClass()) {
2277-
C.Diags.diagnose(ComplainLoc,
2278-
diag::objc_protocol_in_generic_extension,
2279-
classDecl->isGeneric(), T, ProtoType);
2279+
Context.Diags.diagnose(ComplainLoc,
2280+
diag::objc_protocol_in_generic_extension,
2281+
classDecl->isGeneric(), T, ProtoType);
22802282
conformance->setInvalid();
22812283
return;
22822284
}
@@ -2288,22 +2290,24 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
22882290
// Not every protocol/type is compatible with conditional conformances.
22892291
auto conditionalReqs = conformance->getConditionalRequirements();
22902292
if (!conditionalReqs.empty()) {
2291-
auto nestedType = DC->getSelfNominalTypeDecl()->getDeclaredInterfaceType();
2292-
// Obj-C generics cannot be looked up at runtime, so we don't support
2293-
// conditional conformances involving them. Check the full stack of nested
2294-
// types for any obj-c ones.
2295-
while (nestedType) {
2296-
if (auto clazz = nestedType->getClassOrBoundGenericClass()) {
2297-
if (clazz->isTypeErasedGenericClass()) {
2298-
C.Diags.diagnose(ComplainLoc,
2299-
diag::objc_generics_cannot_conditionally_conform, T,
2300-
ProtoType);
2301-
conformance->setInvalid();
2302-
return;
2293+
auto nestedType = DC->getSelfInterfaceType();
2294+
if (nestedType->getAnyNominal()) {
2295+
// Obj-C generics cannot be looked up at runtime, so we don't support
2296+
// conditional conformances involving them. Check the full stack of nested
2297+
// types for any obj-c ones.
2298+
while (nestedType) {
2299+
if (auto clazz = nestedType->getClassOrBoundGenericClass()) {
2300+
if (clazz->isTypeErasedGenericClass()) {
2301+
Context.Diags.diagnose(ComplainLoc,
2302+
diag::objc_generics_cannot_conditionally_conform,
2303+
T, ProtoType);
2304+
conformance->setInvalid();
2305+
return;
2306+
}
23032307
}
2304-
}
23052308

2306-
nestedType = nestedType->getNominalParent();
2309+
nestedType = nestedType->getNominalParent();
2310+
}
23072311
}
23082312

23092313
// If the protocol to which we are conditionally conforming is not a marker
@@ -2313,7 +2317,7 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
23132317
for (const auto &req : conditionalReqs) {
23142318
if (req.getKind() == RequirementKind::Conformance &&
23152319
req.getProtocolDecl()->isMarkerProtocol()) {
2316-
C.Diags.diagnose(
2320+
Context.Diags.diagnose(
23172321
ComplainLoc, diag::marker_protocol_conditional_conformance,
23182322
Proto->getName(), req.getFirstType(),
23192323
req.getProtocolDecl()->getName());
@@ -2332,16 +2336,16 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
23322336
const auto effectiveVers =
23332337
getASTContext().LangOpts.EffectiveLanguageVersion;
23342338
if (serialized->getLanguageVersionBuiltWith() != effectiveVers) {
2335-
C.Diags.diagnose(ComplainLoc,
2336-
diag::protocol_has_missing_requirements_versioned, T,
2337-
ProtoType, serialized->getLanguageVersionBuiltWith(),
2338-
effectiveVers);
2339+
Context.Diags.diagnose(ComplainLoc,
2340+
diag::protocol_has_missing_requirements_versioned,
2341+
T, ProtoType, serialized->getLanguageVersionBuiltWith(),
2342+
effectiveVers);
23392343
hasDiagnosed = true;
23402344
}
23412345
}
23422346
if (!hasDiagnosed) {
2343-
C.Diags.diagnose(ComplainLoc, diag::protocol_has_missing_requirements, T,
2344-
ProtoType);
2347+
Context.Diags.diagnose(ComplainLoc, diag::protocol_has_missing_requirements,
2348+
T, ProtoType);
23452349
}
23462350
conformance->setInvalid();
23472351
return;
@@ -2350,7 +2354,7 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
23502354
// Complain about the use of @unchecked for protocols that don't have
23512355
// additional semantic checks.
23522356
if (conformance->isUnchecked() && !hasAdditionalSemanticChecks(Proto)) {
2353-
C.Diags.diagnose(
2357+
Context.Diags.diagnose(
23542358
ComplainLoc, diag::unchecked_conformance_not_special, ProtoType);
23552359
}
23562360

@@ -2379,12 +2383,35 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
23792383
// should go into the new extension we (might) suggest here.
23802384

23812385
diagnoseConformanceImpliedByConditionalConformance(
2382-
C.Diags, conformance, implyingConf);
2386+
Context.Diags, conformance, implyingConf);
23832387

23842388
conformance->setInvalid();
23852389
}
23862390
}
23872391

2392+
// Except in specific hardcoded cases for Foundation/Swift
2393+
// standard library compatibility, an _ObjectiveCBridgeable
2394+
// conformance must appear in the same module as the definition of
2395+
// the conforming type.
2396+
//
2397+
// Note that we check the module name to smooth over the difference
2398+
// between an imported Objective-C module and its overlay.
2399+
if (Proto->isSpecificProtocol(KnownProtocolKind::ObjectiveCBridgeable)) {
2400+
auto nominal = DC->getSelfNominalTypeDecl();
2401+
if (!Context.isTypeBridgedInExternalModule(nominal)) {
2402+
auto clangLoader = Context.getClangModuleLoader();
2403+
if (nominal->getParentModule() != DC->getParentModule() &&
2404+
!(clangLoader &&
2405+
clangLoader->isInOverlayModuleForImportedModule(DC, nominal))) {
2406+
auto nominalModule = nominal->getParentModule();
2407+
Context.Diags.diagnose(conformance->getLoc(),
2408+
diag::nonlocal_bridged_to_objc,
2409+
nominal->getName(), Proto->getName(),
2410+
nominalModule->getName());
2411+
}
2412+
}
2413+
}
2414+
23882415
// Check that T conforms to all inherited protocols.
23892416
for (auto InheritedProto : Proto->getInheritedProtocols()) {
23902417
auto InheritedConformance =
@@ -2396,8 +2423,8 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
23962423
// Recursive call already diagnosed this problem, but tack on a note
23972424
// to establish the relationship.
23982425
if (ComplainLoc.isValid()) {
2399-
C.Diags.diagnose(Proto, diag::inherited_protocol_does_not_conform, T,
2400-
InheritedProto->getDeclaredInterfaceType());
2426+
Context.Diags.diagnose(Proto, diag::inherited_protocol_does_not_conform,
2427+
T, InheritedProto->getDeclaredInterfaceType());
24012428
}
24022429

24032430
conformance->setInvalid();
@@ -2408,8 +2435,18 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
24082435
if (conformance->isComplete())
24092436
return;
24102437

2411-
ConformanceChecker checker(getASTContext(), conformance);
2412-
checker.checkConformance();
2438+
// Resolve all of the type witnesses.
2439+
evaluateOrDefault(Context.evaluator,
2440+
ResolveTypeWitnessesRequest{conformance},
2441+
evaluator::SideEffect());
2442+
2443+
// Check the requirements from the requirement signature.
2444+
ensureRequirementsAreSatisfied(Context, conformance);
2445+
2446+
// Check non-type requirements.
2447+
evaluateOrDefault(Context.evaluator,
2448+
ResolveValueWitnessesRequest{conformance},
2449+
evaluator::SideEffect());
24132450
}
24142451

24152452
/// Add the next associated type deduction to the string representation
@@ -5034,45 +5071,13 @@ void ConformanceChecker::resolveValueWitnesses() {
50345071
}
50355072
}
50365073

5037-
void ConformanceChecker::checkConformance() {
5038-
assert(!Conformance->isComplete() && "Conformance is already complete");
5039-
5040-
FrontendStatsTracer statsTracer(getASTContext().Stats,
5041-
"check-conformance", Conformance);
5042-
5043-
// Resolve all of the type witnesses.
5044-
evaluateOrDefault(getASTContext().evaluator,
5045-
ResolveTypeWitnessesRequest{Conformance},
5046-
evaluator::SideEffect());
5047-
5048-
// Check the requirements from the requirement signature.
5049-
ensureRequirementsAreSatisfied(getASTContext(), Conformance);
5050-
5051-
// Check non-type requirements.
5052-
resolveValueWitnesses();
5053-
5054-
// Except in specific hardcoded cases for Foundation/Swift
5055-
// standard library compatibility, an _ObjectiveCBridgeable
5056-
// conformance must appear in the same module as the definition of
5057-
// the conforming type.
5058-
//
5059-
// Note that we check the module name to smooth over the difference
5060-
// between an imported Objective-C module and its overlay.
5061-
if (Proto->isSpecificProtocol(KnownProtocolKind::ObjectiveCBridgeable)) {
5062-
auto nominal = DC->getSelfNominalTypeDecl();
5063-
if (!getASTContext().isTypeBridgedInExternalModule(nominal)) {
5064-
auto clangLoader = getASTContext().getClangModuleLoader();
5065-
if (nominal->getParentModule() != DC->getParentModule() &&
5066-
!(clangLoader &&
5067-
clangLoader->isInOverlayModuleForImportedModule(DC, nominal))) {
5068-
auto nominalModule = nominal->getParentModule();
5069-
auto &C = nominal->getASTContext();
5070-
C.Diags.diagnose(Loc, diag::nonlocal_bridged_to_objc,
5071-
nominal->getName(), Proto->getName(),
5072-
nominalModule->getName());
5073-
}
5074-
}
5075-
}
5074+
evaluator::SideEffect
5075+
ResolveValueWitnessesRequest::evaluate(Evaluator &evaluator,
5076+
NormalProtocolConformance *conformance) const {
5077+
auto &ctx = conformance->getDeclContext()->getASTContext();
5078+
ConformanceChecker checker(ctx, conformance);
5079+
checker.resolveValueWitnesses();
5080+
return evaluator::SideEffect();
50765081
}
50775082

50785083
void swift::diagnoseConformanceFailure(Type T,
@@ -5133,16 +5138,23 @@ void swift::diagnoseConformanceFailure(Type T,
51335138
return;
51345139
}
51355140

5136-
// If it is missing the ActorSystem type, suggest adding it:
5137-
auto systemTy = getDistributedActorSystemType(/*actor=*/nominal);
5138-
if (!systemTy || systemTy->hasError()) {
5139-
diags.diagnose(ComplainLoc,
5140-
diag::distributed_actor_conformance_missing_system_type,
5141-
nominal->getName());
5142-
diags.diagnose(nominal->getStartLoc(),
5143-
diag::note_distributed_actor_system_can_be_defined_using_defaultdistributedactorsystem);
5144-
return;
5141+
if (nominal->isDistributedActor()) {
5142+
// If it is missing the ActorSystem type, suggest adding it:
5143+
auto systemTy = getDistributedActorSystemType(/*actor=*/nominal);
5144+
if (!systemTy || systemTy->hasError()) {
5145+
diags.diagnose(ComplainLoc,
5146+
diag::distributed_actor_conformance_missing_system_type,
5147+
nominal->getName());
5148+
diags.diagnose(nominal->getStartLoc(),
5149+
diag::note_distributed_actor_system_can_be_defined_using_defaultdistributedactorsystem);
5150+
}
51455151
}
5152+
5153+
// For a non-class nominal type, we already diagnose the failure in
5154+
// ensureRequirementsAreSatisfied() when the 'Self: AnyObject' requirement
5155+
// fails.
5156+
if (!isa<ClassDecl>(nominal))
5157+
return;
51465158
}
51475159

51485160
// Special case: for enums with a raw type, explain that the failing

0 commit comments

Comments
 (0)